diff --git a/README.md b/README.md
deleted file mode 100644
--- a/README.md
+++ /dev/null
@@ -1,182 +0,0 @@
-How to maintain Haskell Packages in Nix
-=======================================
-
-## Overview over the tool-chain
-
-There are two utilities, `cabal2nix` and `hackage4nix`, that automate
-maintenance to a large extent. We intend to merge them into one program,
-eventually, but the necessary re-factoring hasn't been done yet since
-this is not a high priority.
-
-### Cabal2nix
-
-`cabal2nix` converts a single Cabal file into a single Nix build
-expression. For example:
-
-    $ cabal2nix cabal://yesod-0.9.1
-    { cabal, attoparsecText, blazeBuilder, blazeHtml, hamlet, httpTypes
-    , monadControl, parsec, shakespeareCss, shakespeareJs, text, time
-    , transformers, unixCompat, wai, waiExtra, warp, yesodAuth
-    , yesodCore, yesodForm, yesodJson, yesodPersistent
-    }:
-
-    cabal.mkDerivation (self: {
-      pname = "yesod";
-      version = "0.9.1";
-      sha256 = "1ag3lca75lrriycbscspb5yyishacgxjx0rybc3x4z1dqnkn1r71";
-      isLibrary = true;
-      isExecutable = true;
-      buildDepends = [
-        attoparsecText blazeBuilder blazeHtml hamlet httpTypes monadControl
-        parsec shakespeareCss shakespeareJs text time transformers
-        unixCompat wai waiExtra warp yesodAuth yesodCore yesodForm
-        yesodJson yesodPersistent
-      ];
-      meta = {
-        homepage = "http://www.yesodweb.com/";
-        description = "Creation of type-safe, RESTful web applications";
-        license = self.stdenv.lib.licenses.bsd3;
-        platforms = self.ghc.meta.platforms;
-      };
-    })
-
-Cabal files can be referred to using the magic URL
-`cabal://NAME-VERSION`, which will automatically download the file from
-Hackage. Alternatively, a direct `http://host/path/pkg.cabal` URL can be
-provided, as well as a `file:///local/path/pkg.cabal` URI that doesn't
-depend on network access. However, if the source hash is not already in `cabal2nix`'s cache or
-provided using the `--sha256` option, `cabal2nix` still needs to download the source code to
-compute the hash, which obviously still causes network traffic.
-Run the utility with `--help` to see the complete list of supported command line flags.
-
-To add a new package to Nix, checkout the Nixpkgs project from
-https://github.com/nixos/nixpkgs.git and run
-
-    $ cd pkgs/development/libraries/haskell
-    $ mkdir foo
-    $ cabal2nix cabal://foo-1.0 >foo/default.nix
-
-Then add an appropriate attribute to
-`pkgs/top-level/haskell-packages.nix`, for example:
-
-    foo = callPackage ../development/libraries/haskell/foo {};
-
-`cabal2nix` can also build derivations for projects from other
-sources than hackage. You only need to provide an URI that points
-to a cabal project. The most common usecase for this is probably to
-generate a derivation for a project on the local file system:
-
-    aeson:$ cabal2nix ./.
-    # This file was auto-generated by cabal2nix. Please do NOT edit manually!
-
-    { cabal, attoparsec, blazeBuilder, deepseq, dlist, hashable, HUnit
-    , mtl, QuickCheck, scientific, syb, testFramework
-    , testFrameworkHunit, testFrameworkQuickcheck2, text, time
-    , unorderedContainers, vector
-    }
-
-    cabal.mkDerivation (self: {
-      pname = "aeson";
-      version = "0.7.0.2";
-      src = ./.;
-      buildDepends = [
-        attoparsec blazeBuilder deepseq dlist hashable mtl scientific syb
-        text time unorderedContainers vector
-      ];
-      testDepends = [
-        attoparsec HUnit QuickCheck testFramework testFrameworkHunit
-        testFrameworkQuickcheck2 text time unorderedContainers vector
-      ];
-      meta = {
-        homepage = "https://github.com/bos/aeson";
-        description = "Fast JSON parsing and encoding";
-        license = self.stdenv.lib.licenses.bsd3;
-        platforms = self.ghc.meta.platforms;
-      };
-    })
-
-This derivation will not fetch from hackage, but instead use the directory which
-contains the derivation as the source repository.
-
-`cabal2nix` currently supports the following respository types:
-
-* directory
-* source archive (zip, tar.gz, ...) from http or https URL or local file.
-* git, mercurial, svn or bazaar repository
-
-### Hackage4nix
-
-The `hackage4nix` utility re-generates *all* expressions found in the
-`nixpkgs` database in place. This is useful to ensure that all packages
-have been generated with a recent version of the tool-chain.
-Furthermore, `hackage4nix` adds default settings for the
-`meta.maintainers` and `meta.platforms` attribute if these aren't
-configured yet. Generally speaking, running
-
-    $ hackage4nix pkgs
-
-in your checked-out copy of the Nixpkgs tree should be a *no-op* ---
-i.e. no files should change! If there are changes, these indicate that a
-file has been modified manually, and then these changes must be
-investigated to find out what is going on.
-
-Last but not least, `hackage4nix` generates a list of all updates
-available from Hackage. (Run `cabal update` to make sure that your local
-copy of the Hackage database is up-to-date!) For example:
-
-    $ hackage4nix pkgs
-    The following updates are available:
-
-    WebBits-Html-1.0.1:
-      cabal2nix cabal://WebBits-Html-1.0.2 >pkgs/pkgs/development/libraries/haskell/WebBits-Html/default.nix
-
-    happstack-server-6.1.6:
-      cabal2nix cabal://happstack-server-6.2.1 >pkgs/pkgs/development/libraries/haskell/happstack/happstack-server.nix
-      cabal2nix cabal://happstack-server-6.2.2 >pkgs/pkgs/development/libraries/haskell/happstack/happstack-server.nix
-
-    primitive-0.3.1:
-      cabal2nix cabal://primitive-0.4 >pkgs/pkgs/development/libraries/haskell/primitive/default.nix
-
-    repa-2.1.1.5:
-      cabal2nix cabal://repa-2.1.1.6 >pkgs/pkgs/development/libraries/haskell/repa/default.nix
-
-    unix-compat-0.2.2.1:
-      cabal2nix cabal://unix-compat-0.3 >pkgs/pkgs/development/libraries/haskell/unix-compat/default.nix
-
-    vector-0.7.1:
-      cabal2nix cabal://vector-0.8 >pkgs/pkgs/development/libraries/haskell/vector/default.nix
-
-These updates can be performed automatically by running the `cabal2nix`
-command given by `hackage4nix`. If there is more than one possible
-update, then all of them will be shown. Note, however, that some updates
-break compilation of other packages, because they depend on very
-specific versions of their build inputs, so please be careful when
-performing updates!
-
-## Current State of Affairs
-
-The tool-chain is stable. As of today, 2013-04-12, virtually all Haskell
-packages available in Nix have been generated automatically from their
-Cabal files. There are only a handful of exceptions, which we cannot
-generate because these packages aren't available on Hackage. The list of
-those packages is hard-coded into the
-[`hackage4nix.hs`](https://github.com/NixOS/cabal2nix/blob/master/src/hackage4nix.hs)
-binary in the function `badPackagePaths`.
-
-Furthermore, Hackage4Nix will not re-generate packages that have been
-patched, i.e. that define any of the following attributes:
-
-        (pre|post)Configure
-        (pre|post)Install
-        patchPhase
-        patches
-
-These packages are considered for updates, however.
-
-The complete list of Haskell packages available in Nix is generated by
-the tool [`package-list`](http://github.com/peti/package-list),
-and published at <http://cryp.to/haskell-in-nixpkgs.txt>. Hackage picks
-it up from there and generates links on each package's homepage to the
-corresponding page in Hydra automatically. See [ticket
-875](http://www.haskell.org/pipermail/cabal-devel/2011-August/007714.html) for further
-details.
diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main ( main ) where
-
-import Distribution.Simple
-import Distribution.Simple.LocalBuildInfo ( withPrograms )
-import Distribution.Simple.Program ( userSpecifyArgs )
-
-main :: IO ()
-main = defaultMainWithHooks $
-         simpleUserHooks `modify_haddockHook` \oldHH pkg lbi hooks flags ->
-           (\lbi' -> oldHH pkg lbi' hooks flags) $
-             lbi `modify_withPrograms` \oldWP ->
-               userSpecifyArgs "haddock" ["--optghc=-D__HADDOCK__"] oldWP
-  where
-    modify_haddockHook  hooks f = hooks { haddockHook  = f (haddockHook  hooks) }
-    modify_withPrograms lbi   f = lbi   { withPrograms = f (withPrograms lbi)   }
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,40 @@
+#! /usr/bin/env runhaskell
+
+> module Main ( main ) where
+>
+> import Data.Char
+> import Data.Maybe
+> import Distribution.PackageDescription
+> import Distribution.Simple
+> import Distribution.Simple.LocalBuildInfo
+> import Distribution.Simple.Program
+> import Distribution.Simple.Setup
+>
+> main :: IO ()
+> main = defaultMainWithHooks simpleUserHooks
+>        { hookedPrograms = map simpleProgram programs
+>        , confHook = configure
+>        }
+>
+> programs :: [String]
+> programs = ["nix-instantiate", "nix-build", "nix-env", "nix-store"]
+>
+> configure :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo
+> configure (gpd, hbi) flags = do
+>   lbi' <- confHook simpleUserHooks (gpd, hbi) flags
+>   let paths = map (\p -> (p, maybe p programPath (lookupProgram (simpleProgram p) (withPrograms lbi)))) programs
+>       descr = localPkgDescr lbi'
+>       lib = fromJust (library descr)
+>       libbi = libBuildInfo lib
+>       lbi = lbi' { localPkgDescr = descr
+>                    { library = Just (lib { libBuildInfo = libbi { cppOptions = cppOptions libbi ++ map fmtCppArg paths } })
+>                    }
+>                  }
+>   return lbi
+>
+> fmtCppArg :: (String, FilePath) -> String
+> fmtCppArg (prg, path) = "-DPATH_TO_" ++ map mangle prg ++ "=" ++ show path
+>   where
+>     mangle :: Char -> Char
+>     mangle '-' = '_'
+>     mangle c = toUpper c
diff --git a/cabal2nix.cabal b/cabal2nix.cabal
--- a/cabal2nix.cabal
+++ b/cabal2nix.cabal
@@ -1,107 +1,182 @@
-Name:                   cabal2nix
-Version:                1.73
-Copyright:              Peter Simons, Andres Loeh
-License:                BSD3
-License-File:           LICENSE
-Author:                 Peter Simons <simons@cryp.to>, Andres Loeh <mail@andres-loeh.de>
-Maintainer:             Nix Developers <nix-dev@lists.science.uu.nl>
-Homepage:               http://github.com/NixOS/cabal2nix
-Category:               Distribution
-Synopsis:               Convert Cabal files into Nix build instructions
-Cabal-Version:          >= 1.8
-Build-Type:             Custom
-Tested-With:            GHC >= 7.0.4 && <= 7.8.3
-Data-files:             README.md
-Description:
-  The @cabal2nix@ utility converts Cabal files into Nix build instructions. The
-  commandline syntax is:
-  .
-  > Usage: cabal2nix [options] url-to-cabal-file-or-repo
-  >   -h             --help                   show this help text
-  >   -v             --version                print version
-  >                  --hackage-db=FILEPATH    path to the local hackage db in tar format
-  >                  --sha256=HASH            sha256 hash of source tarball
-  >   -m MAINTAINER  --maintainer=MAINTAINER  maintainer of this package (may be specified multiple times)
-  >   -p PLATFORM    --platform=PLATFORM      supported build platforms (may be specified multiple times)
-  >                  --jailbreak              don't honor version restrictions on build inputs
-  >                  --no-haddock             don't run Haddock when building this package
-  >                  --no-check               don't run regression test suites of this package
-  >                  --no-hyperlink-source    don't add pretty-printed source code to the documentation
-  >
-  > Recognized URI schemes:
-  >
-  >   cabal://pkgname-pkgversion       download the specified package from Hackage
-  >   cabal://pkgname                  download latest version of the specified package from Hackage
-  >   http://host/path                 fetch the Cabal file via HTTP
-  >   file:///local/path               load the Cabal file from the local disk
-  >   /local/path.cabal                abbreviated version of file URI
-  >   <git/svn/bzr/hg URL>             download the source from the specified repository
-  .
-  The only required argument is the path to the cabal file. For example:
-  .
-  > cabal2nix http://hackage.haskell.org/packages/archive/cabal2nix/1.73/cabal2nix.cabal
-  > cabal2nix cabal://cabal2nix-1.73
-  .
-  If the @--sha256@ option has not been specified, cabal2nix calls
-  @nix-prefetch-url@ to determine the hash automatically. This causes
-  network traffic, obviously.
-  .
-  If the argument refers to a source repository instead of a cabal file,
-  cabal2nix will use that source repository to fetch from instead of hackage.
-  Currently, cabal2nix supports directories, archives (fetched via http or https) and
-  git, mercurial, svn or bazaar repositories.
+-- This file has been generated from package.yaml by hpack version 0.14.1.
+--
+-- see: https://github.com/sol/hpack
 
-Source-Repository head
-  Type:                 git
-  Location:             git://github.com/NixOS/cabal2nix.git
+name:           cabal2nix
+version:        2.0
+synopsis:       Convert Cabal files into Nix build instructions.
+description:    Convert Cabal files into Nix build instructions. Users of Nix can install the latest version by running:
+                > nix-env -i cabal2nix
+category:       Distribution, Nix
+homepage:       https://github.com/nixos/cabal2nix#readme
+bug-reports:    https://github.com/nixos/cabal2nix/issues
+author:         Peter Simons,
+                Andres Loeh,
+                Benno Fünfstück,
+                Mateusz Kowalczyk,
+                Mathijs Kwik,
+                Michael Alan Dorman,
+                Shea Levy,
+                Dmitry Malikov,
+                Eric Seidel,
+                Nikolay Amiantov,
+                Aycan iRiCAN,
+                John Wiegley,
+                Philipp Hausmann,
+                Spencer Janssen,
+                William Casarin,
+                Adam Vogt,
+                Bryan Gardiner,
+                Corey O'Connor,
+                Cray Elliott,
+                Felix Kunzmann,
+                Gabriel Ebner,
+                Gergely Risko,
+                John Albietz,
+                John Chee,
+                Jussi Maki,
+                Mark Laws,
+                Mark Wotton,
+                Matvey Aksenov,
+                Nicolas Rolland,
+                Oliver Charles,
+                Pascal Wittmann,
+                Patrick John Wheeler,
+                Raymond Gauthier,
+                Renzo Carbonara,
+                Sibi,
+                Tanner Doshier,
+                Tom Hunger,
+                Viktar Basharymau,
+                danbst,
+                karsten gebbert,
+                laMudri,
+                Александр Цамутали
+maintainer:     Peter Simons <simons@cryp.to>
+license:        BSD3
+license-file:   LICENSE
+tested-with:    GHC > 7.10 && < 8.1
+build-type:     Simple
+cabal-version:  >= 1.10
 
-Executable cabal2nix
-  main-is:              cabal2nix.hs
-  hs-source-dirs:       src
-  Build-Depends:        base >= 3 && < 5, regex-posix, pretty, Cabal >= 1.18,
-                        filepath, directory, process, hackage-db >= 1.11, transformers, deepseq
-  Extensions:           PatternGuards, RecordWildCards, CPP
-  Ghc-Options:          -Wall
-  other-modules:        Cabal2Nix.CorePackages
-                        Cabal2Nix.Flags
-                        Cabal2Nix.Generate
-                        Cabal2Nix.Package
-                        Cabal2Nix.License
-                        Cabal2Nix.Name
-                        Cabal2Nix.Normalize
-                        Cabal2Nix.PostProcess
-                        Cabal2Nix.Version
-                        Distribution.NixOS.Fetch
-                        Distribution.NixOS.Derivation.Cabal
-                        Distribution.NixOS.Derivation.License
-                        Distribution.NixOS.Derivation.Meta
-                        Distribution.NixOS.PrettyPrinting
-                        Distribution.NixOS.Regex
+source-repository head
+  type: git
+  location: https://github.com/nixos/cabal2nix
 
-Executable hackage4nix
-  main-is:              hackage4nix.hs
-  hs-source-dirs:       src
-  Build-Depends:        base >= 3 && < 5, regex-posix, pretty, Cabal >= 1.18,
-                        mtl, containers, directory, filepath, hackage-db >= 1.11,
-                        transformers, process, deepseq
-  Extensions:           PatternGuards, RecordWildCards, CPP
-  Ghc-Options:          -Wall
-  other-modules:        Cabal2Nix.CorePackages
-                        Cabal2Nix.Flags
-                        Cabal2Nix.Generate
-                        Cabal2Nix.License
-                        Cabal2Nix.Name
-                        Cabal2Nix.Normalize
-                        Cabal2Nix.PostProcess
-                        Distribution.NixOS.Fetch
-                        Distribution.NixOS.Derivation.Cabal
-                        Distribution.NixOS.Derivation.License
-                        Distribution.NixOS.Derivation.Meta
-                        Distribution.NixOS.PrettyPrinting
-                        Distribution.NixOS.Regex
+library
+  hs-source-dirs:
+      src
+  ghc-options: -Wall
+  build-depends:
+      aeson
+    , ansi-wl-pprint
+    , base < 5
+    , bytestring
+    , Cabal > 1.24
+    , containers
+    , deepseq >= 1.4
+    , directory
+    , distribution-nixpkgs
+    , filepath
+    , hackage-db
+    , language-nix
+    , lens
+    , optparse-applicative
+    , pretty >= 1.1.2
+    , process
+    , SHA
+    , split
+    , text
+    , transformers
+    , yaml
+  exposed-modules:
+      Distribution.Nixpkgs.Fetch
+      Distribution.Nixpkgs.Haskell
+      Distribution.Nixpkgs.Haskell.BuildInfo
+      Distribution.Nixpkgs.Haskell.Constraint
+      Distribution.Nixpkgs.Haskell.Derivation
+      Distribution.Nixpkgs.Haskell.FromCabal
+      Distribution.Nixpkgs.Haskell.FromCabal.Configuration
+      Distribution.Nixpkgs.Haskell.FromCabal.Flags
+      Distribution.Nixpkgs.Haskell.FromCabal.License
+      Distribution.Nixpkgs.Haskell.FromCabal.Name
+      Distribution.Nixpkgs.Haskell.FromCabal.Normalize
+      Distribution.Nixpkgs.Haskell.FromCabal.PostProcess
+      Distribution.Nixpkgs.Haskell.Hackage
+      Distribution.Nixpkgs.Haskell.OrphanInstances
+      Distribution.Nixpkgs.Haskell.PackageSourceSpec
+  other-modules:
+      Paths_cabal2nix
+  default-language: Haskell2010
 
-Test-Suite doctest-cabal2nix
-  type:                 exitcode-stdio-1.0
-  main-is:              doc-test.hs
-  hs-source-dirs:       test
-  build-depends:        base, doctest
+executable cabal2nix
+  main-is: Main.hs
+  hs-source-dirs:
+      cabal2nix
+  ghc-options: -Wall
+  build-depends:
+      aeson
+    , ansi-wl-pprint
+    , base < 5
+    , bytestring
+    , Cabal > 1.24
+    , containers
+    , deepseq >= 1.4
+    , directory
+    , distribution-nixpkgs
+    , filepath
+    , hackage-db
+    , language-nix
+    , lens
+    , optparse-applicative
+    , pretty >= 1.1.2
+    , process
+    , SHA
+    , split
+    , text
+    , transformers
+    , yaml
+    , cabal2nix
+  other-modules:
+      Paths_cabal2nix
+  default-language: Haskell2010
+
+executable hackage2nix
+  main-is: Main.hs
+  hs-source-dirs:
+      hackage2nix
+  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      aeson
+    , ansi-wl-pprint
+    , base < 5
+    , bytestring
+    , Cabal > 1.24
+    , containers
+    , deepseq >= 1.4
+    , directory
+    , distribution-nixpkgs
+    , filepath
+    , hackage-db
+    , language-nix
+    , lens
+    , optparse-applicative
+    , pretty >= 1.1.2
+    , process
+    , SHA
+    , split
+    , text
+    , transformers
+    , yaml
+    , cabal2nix
+    , monad-par
+    , monad-par-extras
+    , mtl
+    , stackage-types
+    , time
+    , utf8-string
+  other-modules:
+      Paths_cabal2nix
+      HackageGit
+      Stackage
+  default-language: Haskell2010
diff --git a/cabal2nix/Main.hs b/cabal2nix/Main.hs
new file mode 100644
--- /dev/null
+++ b/cabal2nix/Main.hs
@@ -0,0 +1,161 @@
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main ( main ) where
+
+import Control.Exception ( bracket )
+import Control.Lens
+import Data.Maybe ( fromMaybe )
+import qualified Data.Set as Set
+import qualified Distribution.Compat.ReadP as P
+import Distribution.Compiler
+import Distribution.Nixpkgs.Fetch
+import Distribution.Nixpkgs.Haskell
+import Distribution.Nixpkgs.Haskell.FromCabal
+import Distribution.Nixpkgs.Haskell.PackageSourceSpec
+import Distribution.Nixpkgs.Meta
+import Distribution.PackageDescription ( FlagName(..), FlagAssignment )
+import Distribution.Simple.Utils ( lowercase )
+import Distribution.System
+import Distribution.Text
+import Language.Nix
+import Options.Applicative
+import Paths_cabal2nix ( version )
+import System.IO ( hFlush, stdout, stderr )
+import qualified Text.PrettyPrint.ANSI.Leijen as P2 hiding ( (<$>), (<>) )
+import Text.PrettyPrint.HughesPJClass ( Doc, Pretty(..), text, vcat, hcat, semi )
+
+data Options = Options
+  { optSha256 :: Maybe String
+  , optMaintainer :: [String]
+--, optPlatform :: [String]                                         -- TODO: fix command line handling of platforms
+  , optHaddock :: Bool
+  , optDoCheck :: Bool
+  , optJailbreak :: Bool
+  , optRevision :: Maybe String
+  , optHyperlinkSource :: Bool
+  , optEnableLibraryProfiling :: Bool
+  , optEnableExecutableProfiling :: Bool
+  , optEnableProfiling :: Maybe Bool
+  , optExtraArgs :: [String]
+  , optHackageDb :: Maybe FilePath
+  , optNixShellOutput :: Bool
+  , optFlags :: [String]
+  , optCompiler :: CompilerId
+  , optSystem :: Platform
+  , optUrl :: String
+  }
+  deriving (Show)
+
+options :: Parser Options
+options = Options
+          <$> optional (strOption $ long "sha256" <> metavar "HASH" <> help "sha256 hash of source tarball")
+          <*> many (strOption $ long "maintainer" <> metavar "MAINTAINER" <> help "maintainer of this package (may be specified multiple times)")
+--        <*> many (strOption $ long "platform" <> metavar "PLATFORM" <> help "supported build platforms (may be specified multiple times)")
+          <*> flag True False (long "no-haddock" <> help "don't run Haddock when building this package")
+          <*> flag True False (long "no-check" <> help "don't run regression test suites of this package")
+          <*> switch (long "jailbreak" <> help "disregard version restrictions on build inputs")
+          <*> optional (strOption $ long "revision" <> help "revision to use when fetching from VCS")
+          <*> flag True False (long "no-hyperlink-source" <> help "don't generate pretty-printed source code for the documentation")
+          <*> switch (long "enable-library-profiling" <> help "enable library profiling in the generated build")
+          <*> switch (long "enable-executable-profiling" <> help "enable executable profiling in the generated build")
+          <*> optional (switch (long "enable-profiling" <> help "enable both library and executable profiling in the generated build"))
+          <*> many (strOption $ long "extra-arguments" <> help "extra parameters required for the function body")
+          <*> optional (strOption $ long "hackage-db" <> metavar "PATH" <> help "path to the local hackage db in tar format")
+          <*> switch (long "shell" <> help "generate output suitable for nix-shell")
+          <*> many (strOption $ short 'f' <> long "flag" <> help "Cabal flag (may be specified multiple times)")
+          <*> option (readP parse) (long "compiler" <> help "compiler to use when evaluating the Cabal file" <> value buildCompilerId <> showDefaultWith display)
+          <*> option (readP parsePlatform) (long "system" <> help "target system to use when evaluating the Cabal file" <> value buildPlatform <> showDefaultWith display)
+          <*> strArgument (metavar "URI")
+
+readP :: P.ReadP a a -> ReadM a
+readP p = eitherReader $ \s -> case [ r' | (r',"") <- P.readP_to_S p s ] of
+                                    (r:_) -> Right r
+                                    _     -> Left ("invalid value " ++ show s)
+
+parsePlatform :: P.ReadP r Platform
+parsePlatform = do arch <- P.choice [P.string "i686" >> return I386, P.string "x86_64" >> return X86_64]
+                   _ <- P.char '-'
+                   os <- P.choice [P.string "linux" >> return Linux, P.string "darwin" >> return OSX]
+                   return (Platform arch os)
+
+pinfo :: ParserInfo Options
+pinfo = info
+        (   helper
+        <*> infoOption ("cabal2nix " ++ display version) (long "version" <> help "Show version number")
+        <*> options
+        )
+        (  fullDesc
+        <> header "cabal2nix converts Cabal files into build instructions for Nix."
+        <> progDescDoc (Just (P2.vcat
+                     [ P2.text ""
+                     , P2.text "Recognized URI schemes:"
+                     , P2.text ""
+                     , P2.text "  cabal://pkgname-pkgversion     download the specified package from Hackage"
+                     , P2.text "  cabal://pkgname                download latest version of this package from Hackage"
+                     , P2.text "  file:///local/path             load the Cabal file from the local disk"
+                     , P2.text "  /local/path                    abbreviated version of file URI"
+                     , P2.text "  <git/svn/bzr/hg URL>           download the source from the specified repository"
+                     , P2.text ""
+                     , P2.fillSep (map P2.text (words (  "If the URI refers to a cabal file, information for building the package "
+                                                      ++ "will be retrieved from that file, but hackage will be used as a source "
+                                                      ++ "for the derivation. Otherwise, the supplied URI will be used to as the "
+                                                      ++ "souce for the derivation and the information is taken from the cabal file "
+                                                      ++ "at the root of the downloaded source."
+                                                      )))
+                     ]))
+        )
+
+main :: IO ()
+main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
+  Options {..} <- execParser pinfo
+
+  pkg <- getPackage optHackageDb $ Source optUrl (fromMaybe "" optRevision) (maybe UnknownHash Guess optSha256)
+
+  let
+      deriv :: Derivation
+      deriv = fromGenericPackageDescription (const True)
+                                            (\i -> Just (binding # (i, path # [i])))
+                                            optSystem
+                                            (unknownCompilerInfo optCompiler NoAbiTag)
+                                            (readFlagList optFlags)
+                                            []
+                                            (pkgCabal pkg)
+              & src .~ pkgSource pkg
+              & runHaddock .~ optHaddock
+              & jailbreak .~ optJailbreak
+              & hyperlinkSource .~ optHyperlinkSource
+              & enableLibraryProfiling .~ (fromMaybe False optEnableProfiling || optEnableLibraryProfiling)
+              & enableExecutableProfiling .~ (fromMaybe False optEnableProfiling || optEnableExecutableProfiling)
+              & metaSection.maintainers .~ Set.fromList (map (review ident) optMaintainer)
+--            & metaSection.platforms .~ Set.fromList optPlatform
+              & doCheck &&~ optDoCheck
+              & extraFunctionArgs %~ Set.union (Set.fromList ("stdenv":map (review ident) optExtraArgs))
+
+      shell :: Doc
+      shell = vcat
+              [ text "{ nixpkgs ? import <nixpkgs> {}, compiler ? \"default\" }:"
+              , text ""
+              , text "let"
+              , text ""
+              , text "  inherit (nixpkgs) pkgs;"
+              , text ""
+              , hcat [ text "  f = ", pPrint deriv, semi ]
+              , text ""
+              , text "  haskellPackages = if compiler == \"default\""
+              , text "                       then pkgs.haskellPackages"
+              , text "                       else pkgs.haskell.packages.${compiler};"
+              , text ""
+              , text "  drv = haskellPackages.callPackage f {};"
+              , text ""
+              , text "in"
+              , text ""
+              , text "  if pkgs.lib.inNixShell then drv.env else drv"
+              ]
+
+  print (if optNixShellOutput then shell else pPrint deriv)
+
+readFlagList :: [String] -> FlagAssignment
+readFlagList = map tagWithValue
+  where tagWithValue ('-':fname) = (FlagName (lowercase fname), False)
+        tagWithValue fname       = (FlagName (lowercase fname), True)
diff --git a/hackage2nix/HackageGit.hs b/hackage2nix/HackageGit.hs
new file mode 100644
--- /dev/null
+++ b/hackage2nix/HackageGit.hs
@@ -0,0 +1,79 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module HackageGit where
+
+import Control.Monad
+import Control.Lens hiding ( (<.>) )
+import Data.Aeson
+import Data.ByteString.Char8 ( ByteString )
+import qualified Data.ByteString.Char8 as BS
+import Data.ByteString.Lazy.Char8 ( fromStrict )
+import Data.Digest.Pure.SHA ( sha256, showDigest )
+import Data.Map as Map
+import Data.Set as Set
+import Data.String
+import Data.String.UTF8 ( toString, fromRep )
+import Distribution.Nixpkgs.Haskell.OrphanInstances ( )
+import Distribution.Package
+import Distribution.PackageDescription
+import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )
+import Distribution.Text
+import Distribution.Version
+import System.Directory
+import System.FilePath
+
+type Hackage = Map PackageName (Set Version)
+
+readHackage :: FilePath -> IO Hackage
+readHackage path = getSubDirs path >>= foldM discoverPackageVersions mempty
+  where
+    discoverPackageVersions :: Hackage -> String -> IO Hackage
+    discoverPackageVersions db pkg = do
+      vs <- getSubDirs (path </> pkg)
+      return (Map.insert (PackageName pkg) (Set.fromList (Prelude.map fromString vs)) db)
+
+getSubDirs :: FilePath -> IO [FilePath]
+getSubDirs path = do
+  let isDirectory p = doesDirectoryExist (path </> p)
+  getDirectoryContents path >>= filterM isDirectory . Prelude.filter (\x -> head x /= '.')
+
+decodeUTF8 :: ByteString -> String
+decodeUTF8 = toString . fromRep
+
+type SHA256Hash = String
+
+readPackage :: FilePath -> PackageIdentifier -> IO (GenericPackageDescription, SHA256Hash)
+readPackage dirPrefix (PackageIdentifier name version) = do
+  let cabalFile = dirPrefix </> unPackageName name </> display version </> unPackageName name <.> "cabal"
+  buf <- BS.readFile cabalFile
+  cabal <- case parsePackageDescription (decodeUTF8 buf) of
+             ParseOk _ a  -> return a
+             ParseFailed err -> fail (cabalFile ++ ": " ++ show err)
+  return (cabal, mkSHA256 buf)
+
+mkSHA256 :: ByteString -> SHA256Hash
+mkSHA256 = showDigest . sha256 . fromStrict
+
+declareLenses [d|
+  data Meta = Meta { hashes :: Map String String
+                   , locations :: [String]
+                   , pkgsize :: Int
+                   }
+    deriving (Show)
+  |]
+
+instance FromJSON Meta where
+  parseJSON (Object v) = Meta
+                         <$> v .: "package-hashes"
+                         <*> v .: "package-locations"
+                         <*> v .: "package-size"
+  parseJSON o          = fail ("invalid Cabal metadata: " ++ show o)
+
+readPackageMeta :: FilePath -> PackageIdentifier -> IO Meta
+readPackageMeta dirPrefix (PackageIdentifier name version) = do
+  let metaFile = dirPrefix </> unPackageName name </> display version </> unPackageName name <.> "json"
+  buf <- BS.readFile metaFile
+  case eitherDecodeStrict buf of
+    Left msg -> fail (metaFile ++ ": " ++ msg)
+    Right x  -> return x
diff --git a/hackage2nix/Main.hs b/hackage2nix/Main.hs
new file mode 100644
--- /dev/null
+++ b/hackage2nix/Main.hs
@@ -0,0 +1,259 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+
+module Main ( main ) where
+
+import Control.Lens
+import Control.Monad
+import Control.Monad.Par.Combinator
+import Control.Monad.Par.IO
+import Control.Monad.Trans ( liftIO )
+import Data.List
+import Data.Map.Strict ( Map )
+import qualified Data.Map.Strict as Map
+import Data.Maybe
+import Data.Monoid
+import Data.Set ( Set )
+import qualified Data.Set as Set
+import Data.String
+import Distribution.Nixpkgs.Fetch
+import Distribution.Nixpkgs.Haskell as Derivation
+import Distribution.Nixpkgs.Haskell.Constraint
+import Distribution.Nixpkgs.Haskell.FromCabal
+import Distribution.Nixpkgs.Haskell.FromCabal.Configuration as Config
+import Distribution.Nixpkgs.Haskell.FromCabal.Flags
+import Distribution.Nixpkgs.Meta
+import Distribution.Nixpkgs.PackageMap
+import Distribution.Package
+import Distribution.PackageDescription hiding ( options, buildDepends, extraLibs, buildTools )
+import Distribution.System
+import Distribution.Text
+import Distribution.Version
+import HackageGit
+import Language.Nix
+import Options.Applicative
+import qualified Paths_cabal2nix as Main
+import Stackage
+import System.FilePath
+import System.IO
+import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
+
+type PackageSet = Map PackageName Version
+type PackageMultiSet = Map PackageName (Set Version)
+
+data CLI = CLI
+  { hackageRepository :: FilePath
+  , preferredVersionsFile :: Maybe FilePath
+  , nixpkgsRepository :: FilePath
+  , ltsHaskellRepository :: FilePath
+  , stackageNightlyRepository :: FilePath
+  , configFile :: FilePath
+  , targetPlatform :: Platform
+  }
+  deriving (Show)
+
+main :: IO ()
+main = do
+  let cliOptions :: Parser CLI
+      cliOptions = CLI
+        <$> strOption (long "hackage" <> help "path to Hackage git repository" <> value "hackage" <> showDefaultWith id <> metavar "PATH")
+        <*> optional (strOption (long "preferred-versions" <> help "path to Hackage preferred-versions file" <> value "hackage/preferred-versions" <> showDefault <> metavar "PATH"))
+        <*> strOption (long "nixpkgs" <> help "path to Nixpkgs repository" <> value "nixpkgs" <> showDefaultWith id <> metavar "PATH")
+        <*> strOption (long "lts-haskell" <> help "path to LTS Haskell repository" <> value "lts-haskell" <> showDefaultWith id <> metavar "PATH")
+        <*> strOption (long "stackage-nightly" <> help "path to Stackage Nightly repository" <> value "stackage-nightly" <> showDefaultWith id <> metavar "PATH")
+        <*> strOption (long "config" <> help "path to configuration file inside of Nixpkgs" <> value "pkgs/development/haskell-modules/configuration-hackage2nix.yaml" <> showDefaultWith id <> metavar "PATH")
+        <*> option (fmap fromString str) (long "platform" <> help "target platform to generate package set for" <> value "x86_64-linux" <> showDefaultWith display <> metavar "PLATFORM")
+
+      pinfo :: ParserInfo CLI
+      pinfo = info
+              (   helper
+              <*> infoOption ("hackage2nix " ++ display Main.version) (long "version" <> help "Show version number")
+              <*> cliOptions
+              )
+              (  fullDesc
+              <> header "hackage2nix converts a Hackage database into a hackage-packages.nix file."
+              )
+  CLI {..} <- execParser pinfo
+
+  config' <- readConfiguration (nixpkgsRepository </>  configFile)
+  nixpkgs <- readNixpkgPackageMap nixpkgsRepository Nothing
+  preferredVersions <- readPreferredVersions (fromMaybe (hackageRepository </> "preferred-versions") preferredVersionsFile)
+  let fixup = Map.delete "acme-everything"      -- TODO: https://github.com/NixOS/cabal2nix/issues/164
+            . Map.delete "som"                  -- TODO: https://github.com/NixOS/cabal2nix/issues/164
+            . Map.delete "type"                 -- TODO: https://github.com/NixOS/cabal2nix/issues/163
+  hackage <- fixup <$> readHackage hackageRepository
+  snapshots <- runParIO (readLTSHaskell ltsHaskellRepository)
+  nightly <- readStackageNightly stackageNightlyRepository
+  let
+      config :: Configuration
+      config = config' { defaultPackageOverrides = [ Dependency n (thisVersion (Stackage.version spec)) | (n, spec) <- Map.toList (packages nightly) ] }
+
+      hackagePackagesFile :: FilePath
+      hackagePackagesFile = nixpkgsRepository </> "pkgs/development/haskell-modules/hackage-packages.nix"
+
+      corePackageSet :: PackageSet
+      corePackageSet = Map.fromList [ (name, v) | PackageIdentifier name v <- Set.toList (Config.corePackages config) ]
+
+      latestVersionSet :: PackageSet
+      latestVersionSet = Map.map Set.findMax (Map.filter (not . Set.null) (Map.mapWithKey (enforcePreferredVersions preferredVersions) hackage))
+
+      defaultPackageOverridesSet :: PackageSet
+      defaultPackageOverridesSet = Map.fromList [ (name, resolveConstraint c hackage) | c@(Dependency name _) <- defaultPackageOverrides config ]
+
+      generatedDefaultPackageSet :: PackageSet
+      generatedDefaultPackageSet = (defaultPackageOverridesSet `Map.union` latestVersionSet) `Map.difference` corePackageSet
+
+      latestCorePackageSet :: PackageSet
+      latestCorePackageSet = latestVersionSet `Map.intersection` corePackageSet
+
+      latestOverridePackageSet :: PackageSet
+      latestOverridePackageSet = latestVersionSet `Map.intersection` defaultPackageOverridesSet
+
+      extraPackageSet :: PackageMultiSet
+      extraPackageSet = Map.unionsWith Set.union
+                          [ Map.singleton name (Set.singleton (resolveConstraint c hackage)) | c@(Dependency name _) <- extraPackages config ]
+
+      stackagePackageSet :: Map PackageName (Map Version Spec)
+      stackagePackageSet = Map.fromListWith (Map.unionWith mergeSpecs) [ (n, Map.singleton (Stackage.version spec) spec) | snapshot <- nightly:snapshots, (n, spec) <- Map.toList (packages snapshot) ]
+
+      db :: PackageMultiSet
+      db = Map.unionsWith Set.union [ Map.map Set.singleton generatedDefaultPackageSet
+                                    , Map.map Set.singleton latestCorePackageSet
+                                    , Map.map Set.singleton latestOverridePackageSet
+                                    , extraPackageSet
+                                    , Map.map Map.keysSet stackagePackageSet
+                                    ]
+
+      haskellResolver :: Dependency -> Bool
+      haskellResolver (Dependency name vrange)
+        | Just v <- Map.lookup name corePackageSet                = v `withinRange` vrange
+        | Just v <- Map.lookup name generatedDefaultPackageSet    = v `withinRange` vrange
+        | otherwise                                               = False
+
+      nixpkgsResolver :: Identifier -> Maybe Binding
+      nixpkgsResolver = resolve (Map.map (Set.map (over path ("pkgs":))) nixpkgs)
+
+      globalPackageMaintainers :: Map PackageName (Set Identifier)
+      globalPackageMaintainers = Map.unionsWith Set.union [ Map.singleton p (Set.singleton m) | (m,ps) <- Map.toList (packageMaintainers config), p <- Set.toList ps ]
+
+  pkgs <- runParIO $ flip parMapM (Map.toAscList db) $ \(name, vs) -> do
+    defs <- forM (Set.toAscList vs) $ \v -> liftIO $ do
+      let pkgId :: PackageIdentifier
+          pkgId = PackageIdentifier name v
+
+      (descr, cabalSHA256) <- readPackage hackageRepository pkgId
+      meta <- readPackageMeta hackageRepository pkgId
+
+      let isInDefaultPackageSet :: Bool
+          isInDefaultPackageSet = maybe False (== v) (Map.lookup name generatedDefaultPackageSet)
+
+          tarballSHA256 :: SHA256Hash
+          tarballSHA256 = fromMaybe (error (display pkgId ++ ": meta data has no hash for the tarball"))
+                                    (view (hashes . at "SHA256") meta)
+
+          spec :: Spec
+          spec = Spec v True True `fromMaybe` (Map.lookup name stackagePackageSet >>= Map.lookup v)
+
+          flagAssignment :: FlagAssignment                  -- We don't use the flags from Stackage Nightly here, because
+          flagAssignment = configureCabalFlags pkgId        -- they are chosen specifically for GHC 7.10.2.
+
+          attr :: String
+          attr = if isInDefaultPackageSet then unPackageName name else mangle pkgId
+
+          drv :: Derivation
+          drv = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr
+                  & src .~ DerivationSource "url" ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") "" tarballSHA256
+                  & editedCabalFile .~ cabalSHA256
+                  & Derivation.runHaddock &&~ Stackage.runHaddock spec
+                  & doCheck &&~ runTests spec
+                  & metaSection.hydraPlatforms %~ (`Set.difference` Map.findWithDefault Set.empty name (dontDistributePackages config))
+                  & metaSection.maintainers .~ Map.findWithDefault Set.empty name globalPackageMaintainers
+                  & metaSection.hydraPlatforms %~ (if isInDefaultPackageSet then id else const Set.empty)
+
+          overrides :: Doc
+          overrides = fcat $ punctuate space [ disp b <> semi | b <- Set.toList (view (dependencies . each) drv), not (isFromHackage b) ]
+      return $ render $ nest 2 $
+        hang (doubleQuotes (text  attr) <+> equals <+> text "callPackage") 2 (parens (pPrint drv)) <+> (braces overrides <> semi)
+
+    return (intercalate "\n\n" defs)
+
+  withFile hackagePackagesFile WriteMode $ \h -> do
+    hPutStrLn h "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"
+    hPutStrLn h ""
+    hPutStrLn h "{ pkgs, stdenv, callPackage }:"
+    hPutStrLn h ""
+    hPutStrLn h "self: {"
+    hPutStrLn h ""
+    mapM_ (\pkg -> hPutStrLn h pkg >> hPutStrLn h "") pkgs
+    hPutStrLn h "}"
+
+  void $ runParIO $ flip parMapM snapshots $ \Snapshot {..} -> liftIO $ do
+     let allPackages :: PackageSet
+         allPackages = Map.difference
+                         (Map.fromList [ (name, Stackage.version spec) | (name, spec) <- Map.toList packages ] `Map.union` generatedDefaultPackageSet)
+                         corePackages'
+
+         ltsConfigFile :: FilePath
+         ltsConfigFile = nixpkgsRepository </> "pkgs/development/haskell-modules/configuration-" ++ show (pPrint snapshot) ++ ".nix"
+
+         corePackages' :: PackageSet
+         corePackages' = corePackages `Map.union` Map.fromList [("Cabal", Version [] []), ("rts", Version [] [])]
+
+     withFile ltsConfigFile WriteMode $ \h -> do
+       hPutStrLn h "{ pkgs }:"
+       hPutStrLn h ""
+       hPutStrLn h "with import ./lib.nix { inherit pkgs; };"
+       hPutStrLn h ""
+       hPutStrLn h "self: super: {"
+       hPutStrLn h ""
+       hPutStrLn h "  # core libraries provided by the compiler"
+       forM_ (Map.keys corePackages') $ \n ->
+         unless (n == "ghc") (hPutStrLn h ("  " ++ unPackageName n ++ " = null;"))
+       hPutStrLn h ""
+       hPutStrLn h ("  # " ++ show (pPrint snapshot) ++ " packages")
+       forM_ (Map.toList allPackages) $ \(name, v) -> do
+         let pkgId = PackageIdentifier name v
+
+             isInDefaultPackageSet :: Bool
+             isInDefaultPackageSet = maybe False (== v) (Map.lookup name generatedDefaultPackageSet)
+
+             isInStackage :: Bool
+             isInStackage = isJust (Map.lookup name packages)
+         case (isInStackage,isInDefaultPackageSet) of
+           (True,True)   -> return ()           -- build is visible and enabled
+           (True,False)  -> hPutStrLn h ("  " ++ show (unPackageName name) ++ " = doDistribute super." ++ show (mangle pkgId) ++ ";")
+           (False,True)  -> hPutStrLn h ("  " ++ show (unPackageName name) ++ " = dontDistribute super." ++ show (unPackageName name) ++ ";")
+           (False,False) -> fail ("logic error processing " ++ display pkgId ++ " in " ++  show (pPrint snapshot))
+       hPutStrLn h ""
+       hPutStrLn h "}"
+
+
+isFromHackage :: Binding -> Bool
+isFromHackage b = case view (reference . path) b of
+                    ["self",_] -> True
+                    _ -> False
+
+readPreferredVersions :: FilePath -> IO [Constraint]
+readPreferredVersions p = mapMaybe parsePreferredVersionsLine . lines <$> readFile p
+
+parsePreferredVersionsLine :: String -> Maybe Constraint
+parsePreferredVersionsLine [] = Nothing
+parsePreferredVersionsLine ('-':'-':_) = Nothing
+parsePreferredVersionsLine l = simpleParse l `mplus` error ("invalid preferred-versions line: " ++ show l)
+
+enforcePreferredVersions :: [Constraint] -> PackageName -> Set Version -> Set Version
+enforcePreferredVersions cs pkg = Set.filter (\v -> PackageIdentifier pkg v `satisfiesConstraints` cs)
+
+resolveConstraint :: Constraint -> Hackage -> Version
+resolveConstraint c = fromMaybe (error msg) . resolveConstraint' c
+  where msg = "constraint " ++ display c ++ " cannot be resolved in Hackage"
+
+resolveConstraint' :: Constraint -> Hackage -> Maybe Version
+resolveConstraint' (Dependency name vrange) hackage
+  | Just vset' <- Map.lookup name hackage
+  , vset <- Set.filter (`withinRange` vrange) vset'
+  , not (Set.null vset)         = Just (Set.findMax vset)
+  | otherwise                   = Nothing
+
+mangle :: PackageIdentifier -> String
+mangle (PackageIdentifier (PackageName name) v) = name ++ '_' : [ if c == '.' then '_' else c | c <- display v ]
diff --git a/hackage2nix/Stackage.hs b/hackage2nix/Stackage.hs
new file mode 100644
--- /dev/null
+++ b/hackage2nix/Stackage.hs
@@ -0,0 +1,114 @@
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Stackage where
+
+import Control.DeepSeq
+import Control.Exception ( assert )
+import Control.Monad
+import Control.Monad.Par.Combinator
+import Control.Monad.Par.IO
+import Control.Monad.Trans
+import Data.List
+import Data.List.Split
+import Data.Map as Map
+import Data.Maybe
+import Data.Time.Calendar
+import Data.Yaml
+import Distribution.Compiler
+import Distribution.Nixpkgs.Haskell.OrphanInstances ( )
+import Distribution.Package
+import Distribution.Version
+import GHC.Generics ( Generic )
+import Stackage.Types hiding ( display )
+import System.Directory
+import System.FilePath
+import Text.PrettyPrint.HughesPJClass
+
+data Spec = Spec
+            { version :: Version
+  --        , flagOverrides :: Map FlagName Bool
+            , runTests :: Bool
+            , runHaddock :: Bool
+  --        , runLinuxBuilds :: Bool
+            }
+  deriving (Show, Generic)
+
+instance Eq Spec where
+  a == b = version a == version b
+
+instance Ord Spec where
+  compare a b = compare (version a) (version b)
+
+data Snapshot = Snapshot
+            { snapshot :: SnapshotType
+            , compiler :: CompilerId
+            , corePackages :: Map PackageName Version
+            , packages :: Map PackageName Spec
+            }
+  deriving (Show, Generic)
+
+deriving instance Generic SnapshotType
+instance NFData Spec
+instance NFData Snapshot
+instance NFData SnapshotType
+
+instance Pretty SnapshotType where
+  pPrint STNightly = text "stackage-nightly"
+  pPrint (STNightly2 _) = text "stackage-nightly"
+  pPrint (STLTS m n) = text "lts-" <> int m <> char '.' <> int n
+
+readLTSHaskell :: FilePath -> ParIO [Snapshot]
+readLTSHaskell dirPath = do
+  filePaths <- liftIO (listFiles dirPath)
+  parMapM (liftIO . readSnapshot) [ dirPath </> p | p <- filePaths, takeExtension p == ".yaml" ]
+
+readStackageNightly :: FilePath -> IO Snapshot
+readStackageNightly dirPath = do
+  filePaths <- liftIO (listFiles dirPath)
+  let filePath = maximum [ p | p <- filePaths, takeExtension p == ".yaml" ]
+  readSnapshot (dirPath </> filePath)
+
+readSnapshot :: FilePath -> IO Snapshot
+readSnapshot p = fmap (fromBuildPlan (parseSnapshotType (takeFileName p))) (readBuildPlan p)
+
+parseSnapshotType :: FilePath -> SnapshotType
+parseSnapshotType p
+  | "lts-" `isPrefixOf` p
+  , [major,minor] <- splitOn "." (drop 4 (dropExtension p))
+                = STLTS (read major) (read minor)
+  | "nightly-" `isPrefixOf` p
+  , [year,month,day] <- splitOn "-" (drop 8 (dropExtension p))
+                = STNightly2 (fromGregorian (read year) (read month) (read day))
+  | otherwise   = error ("parseSnapshotType: invalid file name " ++ p)
+
+readBuildPlan :: FilePath -> IO BuildPlan
+readBuildPlan = fmap fromJust . decodeFile
+
+fromBuildPlan :: SnapshotType -> BuildPlan -> Snapshot
+fromBuildPlan snt bp = Snapshot snt
+                                (CompilerId GHC (siGhcVersion (bpSystemInfo bp)))
+                                (siCorePackages (bpSystemInfo bp))
+                                (Map.map fromPackagePlan (bpPackages bp))
+
+fromPackagePlan :: PackagePlan -> Spec
+fromPackagePlan pp = Spec (ppVersion pp)
+    --                    (pcFlagOverrides ppc)
+                          (pcTests ppc == ExpectSuccess)
+                          (pcHaddocks ppc == ExpectSuccess)
+    --                    (not (pcSkipBuild ppc))
+  where ppc = ppConstraints pp
+
+listFiles :: FilePath -> IO [FilePath]
+listFiles path = do
+  let isFile p = doesFileExist (path </> p)
+  getDirectoryContents path >>= filterM isFile . Prelude.filter (\x -> head x /= '.')
+
+mergeSpecs :: Spec -> Spec -> Spec
+mergeSpecs a b = Spec { version = assert (version a == version b) version a
+         --           , flagOverrides = flagOverrides a
+                      , runTests = runTests a && runTests b
+                      , runHaddock = runHaddock a && runHaddock b
+         --           , runLinuxBuilds = runLinuxBuilds a
+                      }
diff --git a/src/Cabal2Nix/CorePackages.hs b/src/Cabal2Nix/CorePackages.hs
deleted file mode 100644
--- a/src/Cabal2Nix/CorePackages.hs
+++ /dev/null
@@ -1,43 +0,0 @@
-module Cabal2Nix.CorePackages ( corePackages, coreBuildTools ) where
-
--- | List of packages shipped with ghc and therefore at the moment not in
--- nixpkgs. This should probably be configurable at first. Later, it might
--- be good to actually include them as dependencies, but set them to null
--- if GHC provides them (as different GHC versions vary).
---
--- The commented packages have previously been non-core, so we don't filter
--- them.
-corePackages :: [String]
-corePackages = [
-    "array",
-    "base",
-    "bin-package-db",
-    "bytestring",
-    -- "Cabal",
-    "containers",
-    "directory",
-    -- "extensible-exceptions",
-    "ffi",
-    -- "filepath",
-    "ghc",
-    "ghc-binary",
-    "ghc-prim",
-    "haskell2010", -- new as core, but doesn't work in older GHCs anyway
-    "haskell98",
-    "hpc",
-    "integer-gmp",
-    "old-locale",
-    "old-time",
-    "pretty",
-    "process",
-    -- "random",
-    "template-haskell",
-    -- "time",
-    "unix"
-  ]
-
-coreBuildTools :: [String]
-coreBuildTools = [
-    "ghc",
-    "hsc2hs"
-  ]
diff --git a/src/Cabal2Nix/Flags.hs b/src/Cabal2Nix/Flags.hs
deleted file mode 100644
--- a/src/Cabal2Nix/Flags.hs
+++ /dev/null
@@ -1,31 +0,0 @@
-module Cabal2Nix.Flags ( configureCabalFlags ) where
-
-import Distribution.Package
-import Distribution.PackageDescription
-
-configureCabalFlags :: PackageIdentifier -> FlagAssignment
-configureCabalFlags (PackageIdentifier (PackageName name) _)
- | name == "arithmoi"           = [disable "llvm"]
- | name == "accelerate-examples"= [disable "opencl"]
- | name == "diagrams-builder"   = [enable "cairo", enable "svg", enable "ps", enable "rasterific"]
- | name == "folds"              = [disable "test-hlint"]
- | name == "git-annex"          = [enable "Assistant" , enable "Production"]
- | name == "haskeline"          = [enable "terminfo"]
- | name == "haste-compiler"     = [enable "portable"]
- | name == "hslua"              = [enable "system-lua"]
- | name == "hxt"                = [enable "network-uri"]
- | name == "idris"              = [enable "gmp", enable "ffi"]
- | name == "io-streams"         = [enable "NoInteractiveTests"]
- | name == "pandoc"             = [enable "https", enable "make-pandoc-man-pages"]
- | name == "reactive-banana-wx" = [disable "buildExamples"]
- | name == "snap-server"        = [enable "openssl"]
- | name == "xmobar"             = [enable "all_extensions"]
- | name == "xmonad-extras"      = [disable "with_hlist", enable "with_split", enable "with_parsec"]
- | name == "yi"                 = [enable "pango", enable "vty"]
- | otherwise                    = []
-
-enable :: String -> (FlagName,Bool)
-enable name = (FlagName name, True)
-
-disable :: String -> (FlagName,Bool)
-disable name = (FlagName name, False)
diff --git a/src/Cabal2Nix/Generate.hs b/src/Cabal2Nix/Generate.hs
deleted file mode 100644
--- a/src/Cabal2Nix/Generate.hs
+++ /dev/null
@@ -1,66 +0,0 @@
-module Cabal2Nix.Generate ( cabal2nix ) where
-
-import Cabal2Nix.Flags
-import Cabal2Nix.License
-import Cabal2Nix.Normalize
-import Cabal2Nix.PostProcess
-import Data.Maybe
-import Distribution.Compiler
-import Distribution.NixOS.Derivation.Cabal
-import qualified Distribution.Package as Cabal
-import qualified Distribution.PackageDescription as Cabal
-import Distribution.PackageDescription.Configuration
-import Distribution.System
-
-cabal2nix :: Cabal.GenericPackageDescription -> Derivation
-cabal2nix cabal = normalize $ postProcess MkDerivation
-  { pname          = let Cabal.PackageName x = Cabal.pkgName pkg in x
-  , version        = Cabal.pkgVersion pkg
-  , src            = error "cabal2nix left the src field undefined"
-  , isLibrary      = isJust (Cabal.library tpkg)
-  , isExecutable   = not (null (Cabal.executables tpkg))
-  , extraFunctionArgs = []
-  , buildDepends   = map unDep deps
-  , testDepends    = map unDep tstDeps ++ concatMap Cabal.extraLibs tests
-  , buildTools     = map unDep tools
-  , extraLibs      = libs
-  , pkgConfDeps    = pcs
-  , configureFlags = []
-  , cabalFlags     = configureCabalFlags pkg
-  , runHaddock     = True
-  , jailbreak      = False
-  , doCheck        = True
-  , testTarget     = ""
-  , hyperlinkSource = True
-  , enableSplitObjs = True
-  , phaseOverrides = ""
-  , metaSection    = Meta
-                   { homepage       = Cabal.homepage descr
-                   , description    = Cabal.synopsis descr
-                   , license        = fromCabalLicense (Cabal.license descr)
-                   , platforms      = []
-                   , hydraPlatforms = []
-                   , maintainers    = []
-                   }
-  }
-  where
-    descr   = Cabal.packageDescription cabal
-    pkg     = Cabal.package descr
-    deps    = Cabal.buildDepends tpkg
-    tests   = map Cabal.testBuildInfo (Cabal.testSuites tpkg)
-    libDeps = map Cabal.libBuildInfo (maybeToList (Cabal.library tpkg))
-    exeDeps = map Cabal.buildInfo (Cabal.executables tpkg)
-    tstDeps = concatMap Cabal.buildTools tests ++ concatMap Cabal.pkgconfigDepends tests ++
-              concatMap Cabal.targetBuildDepends tests
-    tools   = concatMap Cabal.buildTools (libDeps ++ exeDeps)
-    libs    = concatMap Cabal.extraLibs (libDeps ++ exeDeps)
-    pcs     = map unDep (concatMap Cabal.pkgconfigDepends (libDeps ++ exeDeps))
-    Right (tpkg, _) = finalizePackageDescription
-                        (configureCabalFlags pkg)
-                        (const True)
-                        (Platform I386 Linux)                   -- shouldn't be hardcoded
-                        (CompilerId GHC (Version [7,6,3] []))   -- dito
-                        [] cabal
-
-unDep :: Cabal.Dependency -> String
-unDep (Cabal.Dependency (Cabal.PackageName x) _) = x
diff --git a/src/Cabal2Nix/License.hs b/src/Cabal2Nix/License.hs
deleted file mode 100644
--- a/src/Cabal2Nix/License.hs
+++ /dev/null
@@ -1,27 +0,0 @@
-module Cabal2Nix.License ( fromCabalLicense ) where
-
-import Distribution.NixOS.Derivation.License
-import Distribution.License ( License(..) )
-import Data.Version
-
-fromCabalLicense :: Distribution.License.License -> Distribution.NixOS.Derivation.License.License
-fromCabalLicense (GPL Nothing)                          = Unknown (Just "GPL")
-fromCabalLicense (GPL (Just (Version [2] [])))          = Known "self.stdenv.lib.licenses.gpl2"
-fromCabalLicense (GPL (Just (Version [3] [])))          = Known "self.stdenv.lib.licenses.gpl3"
-fromCabalLicense (LGPL Nothing)                         = Unknown (Just "LGPL")
-fromCabalLicense (LGPL (Just (Version [2,1] [])))       = Known "self.stdenv.lib.licenses.lgpl21"
-fromCabalLicense (LGPL (Just (Version [2] [])))         = Known "self.stdenv.lib.licenses.lgpl2"
-fromCabalLicense (LGPL (Just (Version [3] [])))         = Known "self.stdenv.lib.licenses.gpl3"
-fromCabalLicense (AGPL Nothing)                         = Unknown (Just "AGPL")
-fromCabalLicense (AGPL (Just (Version [3] [])))         = Known "self.stdenv.lib.licenses.agpl3"
-fromCabalLicense (AGPL (Just (Version [3,0] [])))       = Known "self.stdenv.lib.licenses.agpl3"
-fromCabalLicense (UnknownLicense "BSD2")                = Known "self.stdenv.lib.licenses.bsd2"
-fromCabalLicense BSD3                                   = Known "self.stdenv.lib.licenses.bsd3"
-fromCabalLicense BSD4                                   = Unknown (Just "BSD4")
-fromCabalLicense MIT                                    = Known "self.stdenv.lib.licenses.mit"
-fromCabalLicense PublicDomain                           = Known "self.stdenv.lib.licenses.publicDomain"
-fromCabalLicense AllRightsReserved                      = Known "self.stdenv.lib.licenses.unfree"
-fromCabalLicense (Apache Nothing)                       = Known "self.stdenv.lib.licenses.asl20"
-fromCabalLicense (Apache (Just (Version [2,0] [])))     = Known "self.stdenv.lib.licenses.asl20"
-fromCabalLicense OtherLicense                           = Unknown Nothing
-fromCabalLicense l                                      = error $ "Cabal2Nix.License.fromCabalLicense: unknown license " ++ show l
diff --git a/src/Cabal2Nix/Name.hs b/src/Cabal2Nix/Name.hs
deleted file mode 100644
--- a/src/Cabal2Nix/Name.hs
+++ /dev/null
@@ -1,131 +0,0 @@
-module Cabal2Nix.Name ( toNixName, libNixName, buildToolNixName ) where
-
-import Data.Char
-
--- | Map Cabal names to Nix attribute names.
-toNixName :: String -> String
-toNixName []      = error "toNixName: empty string is not a valid argument"
-toNixName name    = f name
-  where
-    f []                            = []
-    f ('-':c:cs) | c `notElem` "-"  = toUpper c : f cs
-    f ('-':_)                       = error ("unexpected package name " ++ show name)
-    f (c:cs)                        = c : f cs
-
--- | Map libraries to Nix packages.
--- TODO: This should probably be configurable. We also need to consider the
--- possibility of name clashes with Haskell libraries. I have included
--- identity mappings to incicate that I have verified their correctness.
-libNixName :: String -> [String]
-libNixName "adns"                               = return "adns"
-libNixName "alsa"                               = return "alsaLib"
-libNixName "appindicator-0.1"                   = return "appindicator"
-libNixName "appindicator3-0.1"                  = return "appindicator"
-libNixName "asound"                             = return "alsaLib"
-libNixName "awesomium-1.6.5"                    = return "awesomium"
-libNixName "bz2"                                = return "bzip2"
-libNixName "cairo-pdf"                          = return "cairo"
-libNixName "cairo-ps"                           = return "cairo"
-libNixName "cairo"                              = return "cairo"
-libNixName "cairo-svg"                          = return "cairo"
-libNixName "CEGUIBase-0.7.7"                    = return "CEGUIBase"
-libNixName "CEGUIOgreRenderer-0.7.7"            = return "CEGUIOgreRenderer"
-libNixName "clutter-1.0"                        = return "clutter"
-libNixName "crypto"                             = return "openssl"
-libNixName "crypt"                              = []  -- provided by glibc
-libNixName "c++"                                = [] -- What is that?
-libNixName "dl"                                 = []  -- provided by glibc
-libNixName "gconf-2.0"                          = return "gconf"
-libNixName "gdk-2.0"                            = return "gtk"
-libNixName "gdk-pixbuf-2.0"                     = return "gdk_pixbuf"
-libNixName "gdk-x11-2.0"                        = return "gdk_x11"
-libNixName "gio-2.0"                            = return "glib"
-libNixName "glib-2.0"                           = return "glib"
-libNixName "GL"                                 = return "mesa"
-libNixName "GLU"                                = ["freeglut","mesa"]
-libNixName "glut"                               = ["freeglut","mesa"]
-libNixName "gmime-2.4"                          = return "gmime"
-libNixName "gnome-keyring-1"                    = return "gnome_keyring"
-libNixName "gnome-keyring"                      = return "gnome_keyring"
-libNixName "gnome-vfs-2.0"                      = return "gnome_vfs"
-libNixName "gnome-vfs-module-2.0"               = return "gnome_vfs_module"
-libNixName "gobject-2.0"                        = return "glib"
-libNixName "gstreamer-0.10"                     = return "gstreamer"
-libNixName "gstreamer-audio-0.10"               = return "gstreamer-audio"
-libNixName "gstreamer-base-0.10"                = return "gstreamer-base"
-libNixName "gstreamer-controller-0.10"          = return "gstreamer-controller"
-libNixName "gstreamer-dataprotocol-0.10"        = return "gstreamer-dataprotocol"
-libNixName "gstreamer-net-0.10"                 = return "gstreamer-net"
-libNixName "gstreamer-plugins-base-0.10"        = return "gstreamer-plugins-base"
-libNixName "gthread-2.0"                        = return "glib"
-libNixName "gtk+-2.0"                           = return "gtk"
-libNixName "gtk+-3.0"                           = return "gtk3"
-libNixName "gtkglext-1.0"                       = return "gtkglext"
-libNixName "gtksourceview-2.0"                  = return "gtksourceview"
-libNixName "gtksourceview-3.0"                  = return "gtksourceview"
-libNixName "gtk-x11-2.0"                        = return "gtk_x11"
-libNixName "icudata"                            = return "icu"
-libNixName "icui18n"                            = return "icu"
-libNixName "icuuc"                              = return "icu"
-libNixName "idn"                                = return "libidn"
-libNixName "IL"                                 = return "libdevil"
-libNixName "iw"                                 = return "wirelesstools"
-libNixName "jack"                               = return "jack2"
-libNixName "jpeg"                               = return "libjpeg"
-libNixName "libglade-2.0"                       = return "libglade"
-libNixName "libgsasl"                           = return "gsasl"
-libNixName "librsvg-2.0"                        = return "librsvg"
-libNixName "libsoup-gnome-2.4"                  = return "libsoup"
-libNixName "libusb-1.0"                         = return "libusb"
-libNixName "libxml-2.0"                         = return "libxml2"
-libNixName "libzip"                             = return "libzip"
-libNixName "libzmq"                             = return "zeromq"
-libNixName "m"                                  = []  -- in stdenv
-libNixName "mono-2.0"                           = return "mono"
-libNixName "ncursesw"                           = return "ncurses"
-libNixName "notify"                             = return "libnotify"
-libNixName "panelw"                             = return "ncurses"
-libNixName "pangocairo"                         = return "pango"
-libNixName "pcap"                               = return "libpcap"
-libNixName "pcre"                               = return "pcre"
-libNixName "pfs-1.2"                            = return "pfstools"
-libNixName "png"                                = return "libpng"
-libNixName "poppler-glib"                       = return "popplerGlib"
-libNixName "portaudio-2.0"                      = return "portaudio"
-libNixName "pq"                                 = return "postgresql"
-libNixName "pthread"                            = []
-libNixName "python-3.3"                         = return "python3"
-libNixName "ruby1.8"                            = return "ruby"
-libNixName "sane-backends"                      = return "saneBackends"
-libNixName "SDL2-2.0"                           = return "SDL2"
-libNixName "sdl2"                               = return "SDL2"
-libNixName "sndfile"                            = return "libsndfile"
-libNixName "sqlite3"                            = return "sqlite"
-libNixName "ssl"                                = return "openssl"
-libNixName "stdc++.dll"                         = [] -- What is that?
-libNixName "stdc++"                             = [] -- What is that?
-libNixName "systemd-journal"                    = return "systemd"
-libNixName "vte-2.90"                           = return "vte"
-libNixName "webkit-1.0"                         = return "webkit"
-libNixName "webkitgtk-3.0"                      = return "webkitgtk"
-libNixName "X11"                                = return "libX11"
-libNixName "Xext"                               = return "libXext"
-libNixName "xft"                                = return "libXft"
-libNixName "Xi"                                 = return "libXi"
-libNixName "xml2"                               = return "libxml2"
-libNixName "Xpm"                                = return "libXpm"
-libNixName "Xrandr"                             = return "libXrandr"
-libNixName "Xss"                                = return "libXScrnSaver"
-libNixName "Xtst"                               = return "libXtst"
-libNixName "Xxf86vm"                            = return "libXxf86vm"
-libNixName "zmq"                                = return "zeromq"
-libNixName "z"                                  = return "zlib"
-libNixName x                                    = return x
-
--- | Map build tool names to Nix attribute names.
-buildToolNixName :: String -> [String]
-buildToolNixName "cabal"                        = return "cabalInstall"
-buildToolNixName "gtk2hsC2hs"                   = return "gtk2hsBuildtools"
-buildToolNixName "gtk2hsHookGenerator"          = return "gtk2hsBuildtools"
-buildToolNixName "gtk2hsTypeGen"                = return "gtk2hsBuildtools"
-buildToolNixName x                              = return (toNixName x)
diff --git a/src/Cabal2Nix/Normalize.hs b/src/Cabal2Nix/Normalize.hs
deleted file mode 100644
--- a/src/Cabal2Nix/Normalize.hs
+++ /dev/null
@@ -1,70 +0,0 @@
-{-# LANGUAGE RecordWildCards #-}
-
-module Cabal2Nix.Normalize ( normalize, normalizeList ) where
-
-import Distribution.NixOS.Derivation.Cabal
-import Cabal2Nix.Name
-import Cabal2Nix.CorePackages
-import Data.List
-import Data.Char
-import Data.Function
-import Distribution.NixOS.Regex ( regsubmatch )
-
-normalize :: Derivation -> Derivation
-normalize deriv@(MkDerivation {..}) = deriv
-  { buildDepends = normalizeNixNames (filter (`notElem` (pname : corePackages)) buildDepends)
-  , testDepends  = normalizeNixNames (filter (`notElem` (pname : corePackages)) testDepends)
-  , buildTools   = normalizeNixBuildTools (filter (`notElem` coreBuildTools) buildTools)
-  , extraLibs    = normalizeNixLibs extraLibs
-  , pkgConfDeps  = normalizeNixLibs pkgConfDeps
-  , metaSection  = normalizeMeta metaSection
-  }
-
-normalizeMeta :: Meta -> Meta
-normalizeMeta meta@(Meta {..}) = meta
-  { description = normalizeDescription description
-  , maintainers = normalizeMaintainers maintainers
-  , platforms   = normalizePlatforms platforms
-  }
-
-normalizeDescription :: String -> String
-normalizeDescription desc
-  | null desc                                             = []
-  | last desc == '.' && length (filter ('.'==) desc) == 1 = normalizeDescription (init desc)
-  | otherwise                                             = quote (unwords (words desc))
-
-quote :: String -> String
-quote ('\\':c:cs) = '\\' : c : quote cs
-quote ('"':cs)    = '\\' : '"' : quote cs
-quote (c:cs)      = c : quote cs
-quote []          = []
-
-normalizeList :: [String] -> [String]
-normalizeList = nub . sortBy (compare `on` map toLower)
-
-normalizeNixNames :: [String] -> [String]
-normalizeNixNames = normalizeList . map toNixName
-
-normalizeNixLibs :: [String] -> [String]
-normalizeNixLibs = normalizeList . concatMap libNixName
-
-normalizeNixBuildTools :: [String] -> [String]
-normalizeNixBuildTools = normalizeList . concatMap buildToolNixName
-
--- |Strip the "self.ghc.meta.platforms" prefix from platform names, filter
--- duplicates, and sort the resulting list alphabetically.
---
--- >>> normalizeMaintainers ["self.stdenv.lib.maintainers.foobar", "foobar"]
--- ["foobar"]
---
--- >>> normalizeMaintainers ["any.prefix.is.recognized.yo", "abc.def"]
--- ["def","yo"]
-
-normalizeMaintainers :: [String] -> [String]
-normalizeMaintainers maints = normalizeList
-  [ (m `regsubmatch` "^([^.].*\\.)?([^.]+)$") !! 1 | m <- maints ]
-
-normalizePlatforms :: [String] -> [String]
-normalizePlatforms [] = ["self.ghc.meta.platforms"]
-normalizePlatforms plats = normalizeList
-  [ if '.' `elem` p then p else "self.stdenv.lib.platforms." ++ p | p <- plats ]
diff --git a/src/Cabal2Nix/Package.hs b/src/Cabal2Nix/Package.hs
deleted file mode 100644
--- a/src/Cabal2Nix/Package.hs
+++ /dev/null
@@ -1,145 +0,0 @@
-module Cabal2Nix.Package where
-
-import Control.Applicative
-import Control.Monad
-import Control.Monad.IO.Class
-import Control.Monad.Trans.Maybe
-import Data.List ( isSuffixOf, isPrefixOf )
-import Data.Maybe ( listToMaybe )
-import Distribution.NixOS.Derivation.Cabal
-import Distribution.NixOS.Fetch
-import Distribution.Text ( simpleParse )
-import System.Directory ( doesDirectoryExist, doesFileExist, createDirectoryIfMissing, getHomeDirectory, getDirectoryContents )
-import System.Exit ( exitFailure )
-import System.FilePath ( (</>), (<.>) )
-import System.IO ( hPutStrLn, stderr, hPutStr )
-
-import qualified Distribution.Hackage.DB as DB
-import qualified Distribution.Package as Cabal
-import qualified Distribution.PackageDescription as Cabal
-import qualified Distribution.PackageDescription.Parse as Cabal
-import qualified Distribution.ParseUtils as ParseUtils
-
-import qualified Control.Exception as Exception
-
-data Package = Package
-  { source :: DerivationSource
-  , cabal :: Cabal.GenericPackageDescription
-  }
-  deriving (Show)
-
-getPackage :: Maybe String -> Source -> IO Package
-getPackage optHackageDB source = do
-  (derivSource, pkgDesc) <- fetchOrFromDB optHackageDB source
-  flip Package pkgDesc <$> maybe (sourceFromHackage (sourceHash source) $ showPackageIdentifier pkgDesc) return derivSource
-
-
-fetchOrFromDB :: Maybe String -> Source -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription)
-fetchOrFromDB optHackageDB src
-  | "cabal://" `isPrefixOf` sourceUrl src = fmap ((,) Nothing) . fromDB optHackageDB . drop (length "cabal://") $ sourceUrl src
-  | otherwise                             = do
-    r <- fetch cabalFromPath src
-    case r of
-      Nothing ->
-        hPutStrLn stderr "*** failed to fetch source. Does the URL exist?" >> exitFailure
-      Just (derivSource, (externalSource, pkgDesc)) ->
-        return (derivSource <$ guard externalSource, pkgDesc)
-
-fromDB :: Maybe String -> String -> IO Cabal.GenericPackageDescription
-fromDB optHackageDB pkg = do
-  pkgDesc <- (lookupVersion <=< DB.lookup name) <$> maybe DB.readHackage DB.readHackage' optHackageDB
-  case pkgDesc of
-    Just r -> return r
-    Nothing -> hPutStrLn stderr "*** no such package in the cabal database (did you run cabal update?). " >> exitFailure
- where
-  Just pkgId = simpleParse pkg
-  Cabal.PackageName name = Cabal.pkgName pkgId
-  version = Cabal.pkgVersion pkgId
-
-  lookupVersion :: DB.Map DB.Version Cabal.GenericPackageDescription -> Maybe Cabal.GenericPackageDescription
-  lookupVersion
-    | null (versionBranch version) = fmap snd . listToMaybe . reverse . DB.toAscList
-    | otherwise                    = DB.lookup version
-
-
-readFileMay :: String -> IO (Maybe String)
-readFileMay file = do
-  e <- doesFileExist file
-  if e
-    then Just <$> readFile file
-    else return Nothing
-
-hashCachePath :: String -> IO String
-hashCachePath pid = do
-  home <- getHomeDirectory
-  let cacheDir = home </> ".cache/cabal2nix"
-  createDirectoryIfMissing True cacheDir
-  return $ cacheDir </> pid <.> "sha256"
-
-sourceFromHackage :: Maybe String -> String -> IO DerivationSource
-sourceFromHackage optHash pkgId = do
-  cacheFile <- hashCachePath pkgId
-  let cachedHash = MaybeT $ maybe (readFileMay cacheFile) (return . Just) optHash
-      url = "mirror://hackage/" ++ pkgId ++ ".tar.gz"
-
-  -- Use the cached hash (either from cache file or given on cmdline via sha256 opt)
-  -- if available, otherwise download from hackage to compute hash.
-  maybeHash <- runMaybeT $ cachedHash <|> derivHash . fst <$> fetchWith (False, "url", []) (Source url "" Nothing)
-  case maybeHash of
-    Just hash ->
-      -- We need to force the hash here. If we didn't do this, then when reading the
-      -- hash from the cache file, the cache file will still be open for reading
-      -- (because lazy io) when writeFile opens the file again for writing. By forcing
-      -- the hash here, we ensure that the file is closed before opening it again.
-      seq (length hash) $
-      DerivationSource "url" url "" hash <$ writeFile cacheFile hash
-    Nothing -> do
-      hPutStr stderr $ unlines
-        [ "*** cannot compute hash. (Not a hackage project?)"
-        , " If your project is not on hackage, please supply the path to the root directory of"
-        , " the project, not to the cabal file."
-        , ""
-        , " If your project is on hackage but you still want to specify the hash manually, you"
-        , " can use the --sha256 option."
-        ]
-      exitFailure
-
-showPackageIdentifier :: Cabal.GenericPackageDescription -> String
-showPackageIdentifier pkgDesc = name ++ "-" ++ showVersion version where
-  pkgId = Cabal.package . Cabal.packageDescription $ pkgDesc
-  Cabal.PackageName name = Cabal.packageName pkgId
-  version = Cabal.packageVersion pkgId
-
-cabalFromPath :: FilePath -> MaybeT IO (Bool, Cabal.GenericPackageDescription)
-cabalFromPath path = do
-  d <- liftIO $ doesDirectoryExist path
-  (,) d <$> if d
-    then cabalFromDirectory  path
-    else cabalFromFile False path
-
-cabalFromDirectory :: FilePath -> MaybeT IO Cabal.GenericPackageDescription
-cabalFromDirectory dir = do
-  cabals <- liftIO $ getDirectoryContents dir >>= filterM doesFileExist . map (dir </>) . filter (".cabal" `isSuffixOf`)
-  case cabals of
-    [cabalFile] -> cabalFromFile True cabalFile
-    _       -> liftIO $ hPutStrLn stderr "*** found zero or more than one cabal file. Exiting." >> exitFailure
-
-handleIO :: (Exception.IOException -> IO a) -> IO a -> IO a
-handleIO = Exception.handle
-
-cabalFromFile :: Bool -> FilePath -> MaybeT IO Cabal.GenericPackageDescription
-cabalFromFile failHard file =
-  -- readFile throws an error if it's used on binary files which contain sequences
-  -- that do not represent valid characters. To catch that exception, we need to
-  -- wrap the whole block in `catchIO`, because of lazy IO. The `case` will force
-  -- the reading of the file, so we will always catch the expression here.
-  MaybeT $ handleIO (const $ return Nothing) $ do
-    content <- readFile file
-    case Cabal.parsePackageDescription content of
-      Cabal.ParseFailed e | failHard -> do
-        let (line, err) = ParseUtils.locatedErrorMsg e
-            msg = maybe "" ((++ ": ") . show) line ++ err
-        putStrLn $ "*** error parsing cabal file: " ++ msg
-        exitFailure
-      Cabal.ParseFailed _  -> return Nothing
-      Cabal.ParseOk     _ a -> return (Just a)
diff --git a/src/Cabal2Nix/PostProcess.hs b/src/Cabal2Nix/PostProcess.hs
deleted file mode 100644
--- a/src/Cabal2Nix/PostProcess.hs
+++ /dev/null
@@ -1,322 +0,0 @@
-{-# LANGUAGE RecordWildCards #-}
-
-module Cabal2Nix.PostProcess ( postProcess ) where
-
-import Data.List
-import Distribution.NixOS.Derivation.Cabal
-
-postProcess :: Derivation -> Derivation
-postProcess deriv@(MkDerivation {..})
-  | pname == "aeson" && version > Version [0,7] []
-                                = deriv { buildDepends = "blazeBuilder":buildDepends }
-  | pname == "Agda"             = deriv { buildTools = "emacs":buildTools, phaseOverrides = agdaPostInstall }
-  | pname == "alex" && version < Version [3,1] []
-                                = deriv { buildTools = "perl":buildTools }
-  | pname == "alex" && version >= Version [3,1] []
-                                = deriv { buildTools = "perl":"happy":buildTools }
-  | pname == "bindings-GLFW"    = deriv { extraLibs = "libXext":"libXfixes":extraLibs }
-  | pname == "bits-extras"      = deriv { configureFlags = "--ghc-option=-lgcc_s":configureFlags, extraLibs = filter (/= "gcc_s") extraLibs }
-  | pname == "Cabal"            = deriv { phaseOverrides = "preCheck = \"unset GHC_PACKAGE_PATH; export HOME=$NIX_BUILD_TOP\";" }
-  | pname == "cabal2nix"        = deriv { doCheck = True, phaseOverrides = cabal2nixDoCheckHook }
-  | pname == "cabal-bounds"     = deriv { buildTools = "cabalInstall":buildTools }
-  | pname == "cabal-install" && version >= Version [0,14] []
-                                = deriv { phaseOverrides = cabalInstallPostInstall }
-  | pname == "cairo"            = deriv { extraLibs = "pkgconfig":"libc":"cairo":"zlib":extraLibs }
-  | pname == "cookie"           = deriv { phaseOverrides = cookieDoCheckHook }
-  | pname == "cuda"             = deriv { phaseOverrides = cudaConfigurePhase, extraLibs = "cudatoolkit":"nvidia_x11":"self.stdenv.cc":extraLibs }
-  | pname == "darcs"            = deriv { phaseOverrides = darcsInstallPostInstall }
-  | pname == "dns"              = deriv { testTarget = "spec" }
-  | pname == "doctest"          = deriv { runHaddock = True, phaseOverrides = doctestNoHaddock }
-  | pname == "editline"         = deriv { extraLibs = "libedit":extraLibs }
-  | pname == "epic"             = deriv { extraLibs = "gmp":"boehmgc":extraLibs, buildTools = "happy":buildTools }
-  | pname == "either"           = deriv { runHaddock = True, phaseOverrides = eitherNoHaddock }
-  | pname == "ghc-heap-view"    = deriv { phaseOverrides = ghciPostInstall }
-  | pname == "ghc-mod"          = deriv { phaseOverrides = ghcModPostInstall, buildTools = "emacs":"makeWrapper":buildTools }
-  | pname == "ghc-parser"       = deriv { buildTools = "cpphs":"happy":buildTools, phaseOverrides = ghcParserPatchPhase }
-  | pname == "ghc-paths"        = deriv { phaseOverrides = ghcPathsPatches }
-  | pname == "ghc-vis"          = deriv { phaseOverrides = ghciPostInstall }
-  | pname == "git-annex"        = deriv { phaseOverrides = gitAnnexOverrides, buildTools = "git":"rsync":"gnupg1":"curl":"wget":"lsof":"openssh":"which":"bup":"perl":buildTools }
-  | pname == "github-backup"    = deriv { buildTools = "git":buildTools }
-  | pname == "glade"            = deriv { extraLibs = "pkgconfig":"libc":extraLibs, pkgConfDeps = "gtkC":delete "gtk" pkgConfDeps }
-  | pname == "glib"             = deriv { extraLibs = "pkgconfig":"libc":extraLibs }
-  | pname == "gloss-raster"     = deriv { extraLibs = "llvm":extraLibs }
-  | pname == "GLUT"             = deriv { extraLibs = "glut":"libSM":"libICE":"libXmu":"libXi":"mesa":extraLibs }
-  | pname == "graphviz"         = deriv { testDepends = "systemGraphviz":testDepends }
-  | pname == "gtk"              = deriv { extraLibs = "pkgconfig":"libc":extraLibs }
-  | pname == "gtkglext"         = deriv { pkgConfDeps = "pangox_compat":pkgConfDeps }
-  | pname == "gtk2hs-buildtools"= deriv { buildDepends = "hashtables":buildDepends }
-  | pname == "gtksourceview2"   = deriv { extraLibs = "pkgconfig":"libc":extraLibs }
-  | pname == "haddock" && version < Version [2,14] []
-                                = deriv { buildTools = "alex":"happy":buildTools }
-  | pname == "haddock"          = deriv { phaseOverrides = haddockPreCheck }
-  | pname == "hakyll"           = deriv { testDepends = "utillinux":testDepends }
-  | pname == "happy"            = deriv { buildTools = "perl":buildTools }
-  | pname == "haskeline"        = deriv { buildDepends = "utf8String":buildDepends }
-  | pname == "haskell-src"      = deriv { buildTools = "happy":buildTools }
-  | pname == "haskell-src-meta" = deriv { buildDepends = "uniplate":buildDepends }
-  | pname == "HFuse"            = deriv { phaseOverrides = hfusePreConfigure }
-  | pname == "highlighting-kate"= highlightingKatePostProcessing deriv
-  | pname == "hlibgit2"         = deriv { testDepends = "git":testDepends }
-  | pname == "HList"            = deriv { buildTools = "diffutils":buildTools }
-  | pname == "hmatrix"          = deriv { extraLibs = "liblapack":"blas": filter (/= "lapack") extraLibs }
-  | pname == "hmatrix-special"  = deriv { extraLibs = "gsl":extraLibs }
-  | pname == "hoogle"           = deriv { testTarget = "--test-option=--no-net" }
-  | pname == "hspec"            = deriv { doCheck = False }
-  | pname == "hsyslog"          = deriv { phaseOverrides = hsyslogNoHaddock }
-  | pname == "HTTP" && version >= Version [4000,2,14] []
-                                = deriv { runHaddock = True, phaseOverrides = httpNoHaddock }
-  | pname == "GlomeVec"         = deriv { buildTools = "llvm":buildTools }
-  | pname == "idris"            = deriv { buildTools = "happy":buildTools, extraLibs = "gmp":"boehmgc":extraLibs }
-  | pname == "language-c-quote" = deriv { buildTools = "alex":"happy":buildTools }
-  | pname == "language-java"    = deriv { buildDepends = "syb":buildDepends }
-  | pname == "leksah-server"    = deriv { buildDepends = "process-leksah":buildDepends }
-  | pname == "lhs2tex"          = deriv { extraLibs = "texLive":extraLibs, phaseOverrides = lhs2texPostInstall }
-  | pname == "libffi"           = deriv { extraLibs = delete "ffi" extraLibs }
-  | pname == "liquid-fixpoint"  = deriv { buildTools = "ocaml":buildTools }
-  | pname == "llvm-base"        = deriv { extraLibs = "llvm":extraLibs }
-  | pname == "llvm-general"     = deriv { doCheck = False }
-  | pname == "llvm-general-pure"= deriv { doCheck = False }
-  | pname == "MFlow"            = deriv { buildTools = "cpphs":buildTools }
-  | pname == "markdown-unlit"   = deriv { runHaddock = True, phaseOverrides = markdownUnlitNoHaddock }
-  | pname == "multiarg"         = deriv { buildDepends = "utf8String":buildDepends }
-  | pname == "mime-mail"        = deriv { extraFunctionArgs = ["sendmail ? \"sendmail\""], phaseOverrides = mimeMailConfigureFlags }
-  | pname == "mysql"            = deriv { buildTools = "mysqlConfig":buildTools, extraLibs = "zlib":extraLibs }
-  | pname == "ncurses"          = deriv { phaseOverrides = ncursesPatchPhase }
-  | pname == "Omega"            = deriv { testDepends = delete "stdc++" testDepends }
-  | pname == "OpenAL"           = deriv { extraLibs = "openal":extraLibs }
-  | pname == "OpenGL"           = deriv { extraLibs = "mesa":"libX11":extraLibs }
-  | pname == "pandoc"           = deriv { buildDepends = "alex":"happy":buildDepends }
-  | pname == "pango"            = deriv { extraLibs = "pkgconfig":"libc":extraLibs }
-  | pname == "pcap"             = deriv { extraLibs = "libpcap":extraLibs }
-  | pname == "persistent"       = deriv { extraLibs = "sqlite3":extraLibs }
-  | pname == "poppler"          = deriv { extraLibs = "libc":extraLibs }
-  | pname == "purescript"       = deriv { testDepends = "nodejs":testDepends }
-  | pname == "QuickCheck" && version >= Version [2,7,3] []
-                                = deriv { runHaddock = True, phaseOverrides = quickCheckNoHaddock }
-  | pname == "repa-algorithms"  = deriv { extraLibs = "llvm":extraLibs }
-  | pname == "repa-examples"    = deriv { extraLibs = "llvm":extraLibs }
-  | pname == "saltine"          = deriv { extraLibs = map (\x -> if x == "sodium" then "libsodium" else x) extraLibs }
-  | pname == "SDL-image"        = deriv { extraLibs = "SDL_image":extraLibs }
-  | pname == "SDL-mixer"        = deriv { extraLibs = "SDL_mixer":extraLibs }
-  | pname == "SDL-ttf"          = deriv { extraLibs = "SDL_ttf":extraLibs }
-  | pname == "sloane"           = deriv { phaseOverrides = sloanePostInstall }
-  | pname == "split" && version == Version [0,2,2] []
-                                = deriv { doCheck = True, phaseOverrides = splitDoCheck }
-  | pname == "structured-haskell-mode" = deriv { buildTools = "emacs":buildTools, phaseOverrides = structuredHaskellModePostInstall }
-  | pname == "svgcairo"         = deriv { extraLibs = "libc":extraLibs }
-  | pname == "syb" && version == Version [0,4,2] []
-                                = deriv { doCheck = True, phaseOverrides = sybDoCheck }
-  | pname == "tar"              = deriv { runHaddock = True, phaseOverrides = tarNoHaddock }
-  | pname == "terminfo"         = deriv { extraLibs = "ncurses":extraLibs }
-  | pname == "threadscope"      = deriv { configureFlags = "--ghc-options=-rtsopts":configureFlags }
-  | pname == "thyme"            = deriv { buildTools = "cpphs":buildTools }
-  | pname == "transformers" && version >= Version [0,4,1] []
-                                = deriv { runHaddock = True, phaseOverrides = transformersNoHaddock }
-  | pname == "tz"               = deriv { extraFunctionArgs = ["pkgs_tzdata"], phaseOverrides = "preConfigure = \"export TZDIR=${pkgs_tzdata}/share/zoneinfo\";" }
-  | pname == "vacuum"           = deriv { extraLibs = "ghcPaths":extraLibs }
-  | pname == "vector"           = deriv { configureFlags = "${self.stdenv.lib.optionalString self.stdenv.isi686 \"--ghc-options=-msse2\"}":configureFlags }
-  | pname == "wxc"              = deriv { extraLibs = "wxGTK":"mesa":"libX11":extraLibs, phaseOverrides = wxcPostInstall }
-  | pname == "wxcore"           = deriv { extraLibs = "wxGTK":"mesa":"libX11":extraLibs }
-  | pname == "X11" && version >= Version [1,6] []
-                                = deriv { extraLibs = "libXinerama":"libXext":"libXrender":extraLibs }
-  | pname == "X11"              = deriv { extraLibs = "libXinerama":"libXext":extraLibs }
-  | pname == "X11-xft"          = deriv { extraLibs = "pkgconfig":"freetype":"fontconfig":extraLibs
-                                        , configureFlags = "--extra-include-dirs=${freetype}/include/freetype2":configureFlags
-                                        }
-  | pname == "xmonad"           = deriv { phaseOverrides = xmonadPostInstall }
-  | pname == "yi"               = deriv { runHaddock = True, phaseOverrides = yiFixHaddock }
-  | otherwise                   = deriv
-
-cudaConfigurePhase :: String
-cudaConfigurePhase = unlines
-  [ "# Perhaps this should be the default in cabal.nix ..."
-  , "#"
-  , "# The cudatoolkit provides both 64 and 32-bit versions of the"
-  , "# library. GHC's linker fails if the wrong version is found first."
-  , "# We solve this by eliminating lib64 from the path on 32-bit"
-  , "# platforms and putting lib64 first on 64-bit platforms."
-  , "libPaths = if self.stdenv.is64bit then \"lib64 lib\" else \"lib\";"
-  , "configurePhase = ''"
-  , "  for i in Setup.hs Setup.lhs; do"
-  , "    test -f $i && ghc --make $i"
-  , "  done"
-  , "  for p in $extraBuildInputs $propagatedNativeBuildInputs; do"
-  , "    if [ -d \"$p/include\" ]; then"
-  , "      extraLibDirs=\"$extraLibDirs --extra-include-dir=$p/include\""
-  , "    fi"
-  , "    for d in $libPaths; do"
-  , "      if [ -d \"$p/$d\" ]; then"
-  , "        extraLibDirs=\"$extraLibDirs --extra-lib-dir=$p/$d\""
-  , "      fi"
-  , "    done"
-  , "  done"
-  , "  ./Setup configure --verbose --prefix=\"$out\" $libraryProfiling $extraLibDirs $configureFlags"
-  , "'';"
-  ]
-
-ghcModPostInstall :: String
-ghcModPostInstall = unlines
-  [ "configureFlags = \"--datasubdir=${self.pname}-${self.version}\";"
-  , "postInstall = ''"
-  , "  cd $out/share/$pname-$version"
-  , "  make"
-  , "  rm Makefile"
-  , "  cd .."
-  , "  ensureDir \"$out/share/emacs\""
-  , "  mv $pname-$version emacs/site-lisp"
-  , "  wrapProgram $out/bin/ghc-mod --add-flags \\"
-  , "    \"\\$(${self.ghc.GHCGetPackages} ${self.ghc.version} \\\"\\$(dirname \\$0)\\\" \\\"-g -package-db -g\\\")\""
-  , "  wrapProgram $out/bin/ghc-modi --add-flags \\"
-  , "    \"\\$(${self.ghc.GHCGetPackages} ${self.ghc.version} \\\"\\$(dirname \\$0)\\\" \\\"-g -package-db -g\\\")\""
-  , "'';"
-  ]
-
-wxcPostInstall :: String
-wxcPostInstall = unlines
-  [ "postInstall = ''"
-  , "  cp -v dist/build/libwxc.so.${self.version} $out/lib/libwxc.so"
-  , "'';"
-  ]
-
-cabalInstallPostInstall :: String
-cabalInstallPostInstall = unlines
-  [ "postInstall = ''"
-  , "  mkdir $out/etc"
-  , "  mv bash-completion $out/etc/bash_completion.d"
-  , "'';"
-  ]
-
-darcsInstallPostInstall :: String
-darcsInstallPostInstall = unlines
-  [ "postInstall = ''"
-  , "  mkdir -p $out/etc/bash_completion.d"
-  , "  mv contrib/darcs_completion $out/etc/bash_completion.d/darcs"
-  , "'';"
-  ]
-
-highlightingKatePostProcessing :: Derivation -> Derivation
-highlightingKatePostProcessing deriv@(MkDerivation {..}) = deriv
-  { phaseOverrides = "prePatch = \"sed -i -e 's|regex-pcre-builtin >= .*|regex-pcre|' highlighting-kate.cabal\";"
-  , buildDepends = "regex-pcre" : filter (/="regex-pcre-builtin") buildDepends
-  }
-
-xmonadPostInstall :: String
-xmonadPostInstall = unlines
-  [ "postInstall = ''"
-  , "  shopt -s globstar"
-  , "  mkdir -p $out/share/man/man1"
-  , "  mv \"$out/\"**\"/man/\"*.1 $out/share/man/man1/"
-  , "'';"
-  , "patches = ["
-  , "  # Patch to make xmonad use XMONAD_{GHC,XMESSAGE} (if available)."
-  , "  ./xmonad_ghc_var_0.11.patch"
-  , "];"
-  ]
-
-yiFixHaddock :: String
-yiFixHaddock = "noHaddock = self.stdenv.lib.versionOlder self.ghc.version \"7.8\";"
-
-gitAnnexOverrides :: String
-gitAnnexOverrides = unlines
-  [ "preConfigure = \"export HOME=$TEMPDIR\";"
-  , "installPhase = \"./Setup install\";"
-  , "checkPhase = ''"
-  , "  cp dist/build/git-annex/git-annex git-annex"
-  , "  ./git-annex test"
-  , "'';"
-  , "propagatedUserEnvPkgs = [git lsof];"
-  ]
-
-ghciPostInstall :: String
-ghciPostInstall = unlines
-  [ "postInstall = ''"
-  , "  ensureDir \"$out/share/ghci\""
-  , "  ln -s \"$out/share/$pname-$version/ghci\" \"$out/share/ghci/$pname\""
-  , "'';"
-  ]
-
-hfusePreConfigure :: String
-hfusePreConfigure = unlines
-  [ "preConfigure = ''"
-  , "  sed -i -e \"s@  Extra-Lib-Dirs:         /usr/local/lib@  Extra-Lib-Dirs:         ${fuse}/lib@\" HFuse.cabal"
-  , "'';"
-  ]
-
-ghcPathsPatches :: String
-ghcPathsPatches = "patches = [ ./ghc-paths-nix.patch ];"
-
-lhs2texPostInstall :: String
-lhs2texPostInstall = unlines
-  [ "postInstall = ''"
-  , "  mkdir -p \"$out/share/doc/$name\""
-  , "  cp doc/Guide2.pdf $out/share/doc/$name"
-  , "  mkdir -p \"$out/nix-support\""
-  , "'';"
-  ]
-
-ncursesPatchPhase :: String
-ncursesPatchPhase = "patchPhase = \"find . -type f -exec sed -i -e 's|ncursesw/||' {} \\\\;\";"
-
-doctestNoHaddock, markdownUnlitNoHaddock :: String
-markdownUnlitNoHaddock = "noHaddock = self.stdenv.lib.versionOlder self.ghc.version \"7.4\";"
-doctestNoHaddock = markdownUnlitNoHaddock
-
-cabal2nixDoCheckHook :: String
-cabal2nixDoCheckHook = "doCheck = self.stdenv.lib.versionOlder \"7.8\" self.ghc.version;"
-
-cookieDoCheckHook :: String
-cookieDoCheckHook = "doCheck = self.stdenv.lib.versionOlder \"7.8\" self.ghc.version;"
-
-eitherNoHaddock :: String
-eitherNoHaddock = "noHaddock = self.stdenv.lib.versionOlder self.ghc.version \"7.6\";"
-
-httpNoHaddock, quickCheckNoHaddock, tarNoHaddock, transformersNoHaddock, hsyslogNoHaddock :: String
-httpNoHaddock = "noHaddock = self.stdenv.lib.versionOlder self.ghc.version \"6.11\";"
-quickCheckNoHaddock = httpNoHaddock
-tarNoHaddock = httpNoHaddock
-transformersNoHaddock = httpNoHaddock
-hsyslogNoHaddock = httpNoHaddock
-
-agdaPostInstall :: String
-agdaPostInstall = unlines
-  [ "postInstall = ''"
-  , "  $out/bin/agda -c --no-main $(find $out/share -name Primitive.agda)"
-  , "  $out/bin/agda-mode compile"
-  , "'';"
-  ]
-
-structuredHaskellModePostInstall :: String
-structuredHaskellModePostInstall = unlines
-  [ "postInstall = ''"
-  , "  emacs -L elisp --batch -f batch-byte-compile \"elisp/\"*.el"
-  , "  install -d $out/share/emacs/site-lisp"
-  , "  install \"elisp/\"*.el \"elisp/\"*.elc  $out/share/emacs/site-lisp"
-  , "'';"
-  ]
-
-sloanePostInstall :: String
-sloanePostInstall = unlines
-  [ "postInstall = ''"
-  , "  mkdir -p $out/share/man/man1"
-  , "  cp sloane.1 $out/share/man/man1/"
-  , "'';"
-  ]
-
-mimeMailConfigureFlags :: String
-mimeMailConfigureFlags = unlines
-  [ "configureFlags = \"--ghc-option=-DMIME_MAIL_SENDMAIL_PATH=\\\"${sendmail}\\\"\";"
-  ]
-
-sybDoCheck, splitDoCheck :: String
-sybDoCheck = "doCheck = self.stdenv.lib.versionOlder self.ghc.version \"7.9\";"
-splitDoCheck = sybDoCheck
-
-haddockPreCheck :: String
-haddockPreCheck = "preCheck = \"unset GHC_PACKAGE_PATH\";"
-
-ghcParserPatchPhase :: String
-ghcParserPatchPhase = unlines
-  [ "patchPhase = ''"
-  , "  substituteInPlace build-parser.sh --replace \"/bin/bash\" \"$SHELL\""
-  , "'';"
-  ]
diff --git a/src/Cabal2Nix/Version.hs b/src/Cabal2Nix/Version.hs
deleted file mode 100644
--- a/src/Cabal2Nix/Version.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Cabal2Nix.Version where
-
-import Data.Version (showVersion)
-import Paths_cabal2nix (version)
-
-version :: String
-version = showVersion Paths_cabal2nix.version
diff --git a/src/Distribution/NixOS/Derivation/Cabal.hs b/src/Distribution/NixOS/Derivation/Cabal.hs
deleted file mode 100644
--- a/src/Distribution/NixOS/Derivation/Cabal.hs
+++ /dev/null
@@ -1,195 +0,0 @@
-{-# LANGUAGE PatternGuards, RecordWildCards, CPP #-}
-{- |
-   Module      :  Distribution.NixOS.Derivation.Cabal
-   License     :  BSD3
-
-   Maintainer  :  nix-dev@cs.uu.nl
-   Stability   :  provisional
-   Portability :  PatternGuards
-
-   A represtation of Nix expressions based on Cabal builder defined in
-   @pkgs\/development\/libraries\/haskell\/cabal\/cabal.nix@.
--}
-
-module Distribution.NixOS.Derivation.Cabal
-  ( Derivation(..)
-  , parseDerivation
-  , DerivationSource(..)
-  , module Distribution.NixOS.Derivation.Meta
-  , module Data.Version
-  )
-  where
-
-import Control.DeepSeq
-import Data.Char
-import Data.Function
-import Data.List
-import Data.Version
-import Distribution.NixOS.Derivation.Meta
-import Distribution.NixOS.Fetch
-import Distribution.NixOS.PrettyPrinting
-import Distribution.NixOS.Regex hiding ( empty )
-import Distribution.Package
-#ifdef __HADDOCK__
-import Distribution.PackageDescription ( PackageDescription )
-#endif
-import Distribution.PackageDescription ( FlagAssignment, FlagName(..) )
-import Distribution.Text
-
--- | A represtation of Nix expressions for building Haskell packages.
--- The data type correspond closely to the definition of
--- 'PackageDescription' from Cabal.
---
--- Note that the "Text" instance definition provides pretty-printing,
--- but no parsing as of now!
-data Derivation = MkDerivation
-  { pname               :: String
-  , version             :: Version
-  , src                 :: DerivationSource
-  , isLibrary           :: Bool
-  , isExecutable        :: Bool
-  , extraFunctionArgs   :: [String]
-  , buildDepends        :: [String]
-  , testDepends         :: [String]
-  , buildTools          :: [String]
-  , extraLibs           :: [String]
-  , pkgConfDeps         :: [String]
-  , configureFlags      :: [String]
-  , cabalFlags          :: FlagAssignment
-  , runHaddock          :: Bool
-  , jailbreak           :: Bool
-  , doCheck             :: Bool
-  , testTarget          :: String
-  , hyperlinkSource     :: Bool
-  , enableSplitObjs     :: Bool
-  , phaseOverrides      :: String
-  , metaSection         :: Meta
-  }
-  deriving (Show, Eq, Ord)
-
-instance Text Derivation where
-  disp  = renderDerivation
-  parse = error "parsing Distribution.NixOS.Derivation.Cabal.Derivation is not supported yet"
-
-instance Package Derivation where
-  packageId deriv = PackageIdentifier (PackageName (pname deriv)) (version deriv)
-
-instance NFData Derivation where
-  rnf (MkDerivation a b c d e f g h i j k l m n o p q r t u v) =
-    a `deepseq` b `deepseq` c `deepseq` d `deepseq` e `deepseq` f `deepseq` g `deepseq`
-    h `deepseq` i `deepseq` j `deepseq` k `deepseq` l `deepseq` m `deepseqFlagAssignment` n `deepseq`
-    o `deepseq` p `deepseq` q `deepseq` r `deepseq` t `deepseq` u `deepseq` v `deepseq` ()
-
--- FlagName has no NFData instance in old version of Cabal.
-deepseqFlagAssignment :: FlagAssignment -> a -> a
-deepseqFlagAssignment [] b = b
-deepseqFlagAssignment ((FlagName n, v):as) b = n `deepseq` v `deepseq` as `deepseqFlagAssignment` b
-
-renderDerivation :: Derivation -> Doc
-renderDerivation deriv =
-  text "# This file was auto-generated by cabal2nix. Please do NOT edit manually!" $$
-  text "" $$
-  funargs (map text ("cabal" : inputs)) $$ vcat
-  [ text ""
-  , text "cabal.mkDerivation" <+> lparen <> text "self" <> colon <+> lbrace
-  , nest 2 $ vcat
-    [ attr "pname"   $ string (pname deriv)
-    , attr "version" $ doubleQuotes (disp (version deriv))
-    , sourceAttr (src deriv)
-    , boolattr "isLibrary" (not (isLibrary deriv) || isExecutable deriv) (isLibrary deriv)
-    , boolattr "isExecutable" (not (isLibrary deriv) || isExecutable deriv) (isExecutable deriv)
-    , listattr "buildDepends" empty (buildDepends deriv)
-    , listattr "testDepends" empty (testDepends deriv)
-    , listattr "buildTools" empty (buildTools deriv)
-    , listattr "extraLibraries" empty (extraLibs deriv)
-    , listattr "pkgconfigDepends" empty (pkgConfDeps deriv)
-    , onlyIf renderedFlags $ attr "configureFlags" $ doubleQuotes (sep renderedFlags)
-    , boolattr "enableSplitObjs"  (not (enableSplitObjs deriv)) (enableSplitObjs deriv)
-    , boolattr "noHaddock" (not (runHaddock deriv)) (not (runHaddock deriv))
-    , boolattr "jailbreak" (jailbreak deriv) (jailbreak deriv)
-    , boolattr "doCheck" (not (doCheck deriv)) (doCheck deriv)
-    , onlyIf (testTarget deriv) $ attr "testTarget" $ string (testTarget deriv)
-    , boolattr "hyperlinkSource" (not (hyperlinkSource deriv)) (hyperlinkSource deriv)
-    , onlyIf (phaseOverrides deriv) $ vcat ((map text . lines) (phaseOverrides deriv))
-    , disp (metaSection deriv)
-    ]
-  , rbrace <> rparen
-  , text ""
-  ]
-  where
-    inputs = nub $ sortBy (compare `on` map toLower) $ filter (/="cabal") $ filter (not . isPrefixOf "self.") $
-              buildDepends deriv ++ testDepends deriv ++ buildTools deriv ++ extraLibs deriv ++ pkgConfDeps deriv ++ extraFunctionArgs deriv
-           ++ ["fetch" ++ derivKind (src deriv) | derivKind (src deriv) /= "" && not isHackagePackage]
-    renderedFlags =  [ text "-f" <> (if enable then empty else char '-') <> text f | (FlagName f, enable) <- cabalFlags deriv ]
-                  ++ map text (configureFlags deriv)
-    isHackagePackage = "mirror://hackage/" `isPrefixOf` derivUrl (src deriv)
-    sourceAttr (DerivationSource{..})
-      | isHackagePackage = attr "sha256" $ string derivHash
-      | derivKind /= "" = vcat
-         [ text "src" <+> equals <+> text ("fetch" ++ derivKind) <+> lbrace
-         , nest 2 $ vcat
-           [ attr "url" $ string derivUrl
-           , attr "sha256" $ string derivHash
-           , if derivRevision /= "" then attr "rev" (string derivRevision) else empty
-           ]
-         , rbrace <> semi
-         ]
-      | otherwise = attr "src" $ text derivUrl
-
--- | A very incomplete parser that extracts 'pname', 'version',
--- 'sha256', 'platforms', 'hydraPlatforms', 'maintainers', 'doCheck',
--- 'jailbreak', and 'runHaddock' from the given Nix expression.
-parseDerivation :: String -> Maybe Derivation
-parseDerivation buf
-  | buf =~ "cabal.mkDerivation"
-  , [name]    <- buf `regsubmatch` "pname *= *\"([^\"]+)\""
-  , [vers']   <- buf `regsubmatch` "version *= *\"([^\"]+)\""
-  , Just vers <- simpleParse vers'
-  , sha       <- buf `regsubmatch` "sha256 *= *\"([^\"]+)\""
-  , sr        <- buf `regsubmatch` "src *= *([^;]+);"
-  , url       <- buf `regsubmatch` "url *= *\"?([^;\"]+)\"? *;"
-  , rev       <- buf `regsubmatch` "rev *= *\"([^\"]+)\""
-  , hplats    <- buf `regsubmatch` "hydraPlatforms *= *([^;]+);"
-  , plats     <- buf `regsubmatch` "platforms *= *([^;]+);"
-  , maint     <- buf `regsubmatch` "maintainers *= *(with [^;]+;)? \\[([^\"]+)]"
-  , noHaddock <- buf `regsubmatch` "noHaddock *= *(true|false) *;"
-  , jailBreak <- buf `regsubmatch` "jailbreak *= *(true|false) *;"
-  , docheck   <- buf `regsubmatch` "doCheck *= *(true|false) *;"
-  , hyperlSrc <- buf `regsubmatch` "hyperlinkSource *= *(true|false) *;"
-  , splitObj  <- buf `regsubmatch` "enableSplitObjs *= *(true|false) *;"
-              = Just MkDerivation
-                  { pname          = name
-                  , version        = vers
-                  , src            = case (sr,url) of
-                                       ([]   , _      ) -> DerivationSource "url" ("mirror://hackage/" ++ name ++ "-" ++ vers' ++ ".tar.gz") "" $ head sha
-                                       (sr':_, []     ) -> DerivationSource "" sr' "" ""
-                                       (sr':_, url':_ ) -> DerivationSource (drop (length "fetch") . head . words $ sr')
-                                                                           url' (head $ rev ++ [""]) $ head sha
-
-                  , isLibrary      = False
-                  , isExecutable   = False
-                  , extraFunctionArgs = []
-                  , buildDepends   = []
-                  , testDepends    = []
-                  , buildTools     = []
-                  , extraLibs      = []
-                  , pkgConfDeps    = []
-                  , configureFlags = []
-                  , cabalFlags     = []
-                  , runHaddock     = noHaddock /= ["true"]
-                  , jailbreak      = jailBreak == ["true"]
-                  , doCheck        = docheck == ["true"] || null docheck
-                  , testTarget     = ""
-                  , hyperlinkSource = hyperlSrc == ["true"] || null hyperlSrc
-                  , enableSplitObjs = splitObj  /= ["false"]
-                  , phaseOverrides = ""
-                  , metaSection  = Meta
-                                   { homepage       = ""
-                                   , description    = ""
-                                   , license        = Unknown Nothing
-                                   , maintainers    = if null maint then [] else concatMap words (tail maint)
-                                   , platforms      = concatMap words (map (map (\c -> if c == '+' then ' ' else c)) plats)
-                                   , hydraPlatforms = concatMap words (map (map (\c -> if c == '+' then ' ' else c)) hplats)
-                                   }
-                  }
-  | otherwise = Nothing
diff --git a/src/Distribution/NixOS/Derivation/License.hs b/src/Distribution/NixOS/Derivation/License.hs
deleted file mode 100644
--- a/src/Distribution/NixOS/Derivation/License.hs
+++ /dev/null
@@ -1,56 +0,0 @@
-{- |
-   Module      :  Distribution.NixOS.Derivation.License
-   License     :  BSD3
-
-   Maintainer  :  nix-dev@cs.uu.nl
-   Stability   :  provisional
-   Portability :  portable
-
-   Known licenses in Nix expressions are represented using the
-   attributes defined in @pkgs\/lib\/licenses.nix@, and unknown licenses
-   are represented as a literal string.
- -}
-
-module Distribution.NixOS.Derivation.License ( License(..) ) where
-
-import Control.DeepSeq
-import Data.Maybe
-import Distribution.NixOS.PrettyPrinting
-import Distribution.Text
-
--- | The representation for licenses used in Nix derivations. Known
--- licenses are Nix expressions -- such as @stdenv.lib.licenses.bsd3@
--- --, so their exact \"name\" is not generally known, because the path
--- to @stdenv@ depends on the context defined in the expression. In
--- Cabal expressions, for example, the BSD3 license would have to be
--- referred to as @self.stdenv.lib.licenses.bsd3@. Other expressions,
--- however, use different paths to the @licenses@ record.. Because of
--- this station, this library cannot provide an abstract data type that
--- encompasses all known licenses. Instead, the @License@ type just
--- distinguishes references to known and unknown licenses. The
--- difference between the two is in the way they are pretty-printed:
---
--- > > putStrLn (display (Known "stdenv.lib.license.gpl2"))
--- > stdenv.lib.license.gpl2
--- >
--- > > putStrLn (display (Unknown (Just "GPL")))
--- > "GPL"
--- >
--- > > putStrLn (display (Unknown Nothing))
--- > "unknown"
---
--- Note that the "Text" instance definition provides pretty-printing,
--- but no parsing as of now!
-
-data License = Known String
-             | Unknown (Maybe String)
-  deriving (Show, Eq, Ord)
-
-instance Text License where
-  disp (Known x)   = text x
-  disp (Unknown x) = string (fromMaybe "unknown" x)
-  parse = error "parsing Distribution.NixOS.Derivation.License is not supported yet"
-
-instance NFData License where
-  rnf (Known s) = rnf s
-  rnf (Unknown s) = rnf s
diff --git a/src/Distribution/NixOS/Derivation/Meta.hs b/src/Distribution/NixOS/Derivation/Meta.hs
deleted file mode 100644
--- a/src/Distribution/NixOS/Derivation/Meta.hs
+++ /dev/null
@@ -1,80 +0,0 @@
-{- |
-   Module      :  Distribution.NixOS.Derivation.Meta
-   License     :  BSD3
-
-   Maintainer  :  nix-dev@cs.uu.nl
-   Stability   :  provisional
-   Portability :  portable
-
-   A representation of the @meta@ section used in Nix expressions. A
-   detailed description can be found in section 4, \"Meta-attributes\",
-   of the Nixpkgs manual at <http://nixos.org/nixpkgs/docs.html>.
- -}
-
-module Distribution.NixOS.Derivation.Meta
-  ( Meta(..)
-  , module Distribution.NixOS.Derivation.License
-  )
-  where
-
-import Control.DeepSeq
-import Distribution.NixOS.Derivation.License
-import Distribution.NixOS.PrettyPrinting
-import Distribution.Text
-
--- | A representation of the @meta@ section used in Nix expressions.
---
--- >>> :{
---   putStrLn (display (Meta "http://example.org" "an example package" (Unknown Nothing)
---                      ["stdenv.lib.platforms."++x | x <- ["unix","cygwin"]]
---                      ["stdenv.lib.platforms.none"]
---                      ["joe","jane"]))
--- :}
--- meta = {
---   homepage = "http://example.org";
---   description = "an example package";
---   license = "unknown";
---   platforms = stdenv.lib.platforms.unix ++ stdenv.lib.platforms.cygwin;
---   hydraPlatforms = stdenv.lib.platforms.none;
---   maintainers = with self.stdenv.lib.maintainers; [ joe jane ];
--- };
---
--- Note that the "Text" instance definition provides pretty-printing,
--- but no parsing as of now!
-
-data Meta = Meta
-  { homepage       :: String    -- ^ URL of the package homepage
-  , description    :: String    -- ^ short description of the package
-  , license        :: License   -- ^ licensing terms
-  , platforms      :: [String]  -- ^ list of supported platforms (from @pkgs\/lib\/platforms.nix@)
-  , hydraPlatforms :: [String]  -- ^ list of platforms built by Hydra (from @pkgs\/lib\/platforms.nix@)
-  , maintainers    :: [String]  -- ^ list of maintainers from @pkgs\/lib\/maintainers.nix@
-  }
-  deriving (Show, Eq, Ord)
-
-instance Text Meta where
-  disp  = renderMeta
-  parse = error "parsing Distribution.NixOS.Derivation.Cabal.Meta is not supported yet"
-
-instance NFData Meta where
-  rnf (Meta a b c d e f) = a `deepseq` b `deepseq` c `deepseq` d `deepseq` e `deepseq` f `deepseq` ()
-
-renderMeta :: Meta -> Doc
-renderMeta meta = vcat
-  [ text "meta" <+> equals <+> lbrace
-  , nest 2 $ vcat
-    [ onlyIf (homepage meta) $ attr "homepage" $ string (homepage meta)
-    , onlyIf (description meta) $ attr "description" $ string (description meta)
-    , attr "license" $ disp (license meta)
-    , onlyIf (platforms meta) $ sep
-      [ text "platforms" <+> equals, renderPlatformList (platforms meta) ]
-    , onlyIf (hydraPlatforms meta) $ sep
-      [ text "hydraPlatforms" <+> equals, renderPlatformList (hydraPlatforms meta) ]
-    , listattr "maintainers" (text "with self.stdenv.lib.maintainers;") (maintainers meta)
-    ]
-  , rbrace <> semi
-  ]
-
-renderPlatformList :: [String] -> Doc
-renderPlatformList plats =
-  nest 2 (fsep $ punctuate (text " ++") $ map text plats) <> semi
diff --git a/src/Distribution/NixOS/Fetch.hs b/src/Distribution/NixOS/Fetch.hs
deleted file mode 100644
--- a/src/Distribution/NixOS/Fetch.hs
+++ /dev/null
@@ -1,142 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-module Distribution.NixOS.Fetch
-  ( Source(..)
-  , DerivationSource(..), fromDerivationSource
-  , fetch
-  , fetchWith
-  ) where
-
-import Control.Applicative
-import Control.DeepSeq
-import Control.Monad
-import Control.Monad.IO.Class
-import Control.Monad.Trans.Maybe
-import Data.Maybe
-import System.Directory
-import System.Environment
-import System.Exit
-import System.IO
-import System.Process
-
--- | A source is a location from which we can fetch, such as a HTTP URL, a GIT URL, ....
-data Source = Source
-  { sourceUrl       :: String       -- ^ URL to fetch from.
-  , sourceRevision  :: String       -- ^ Revision to use. For protocols where this doesn't make sense (such as HTTP), this
-                                    --   should be the empty string.
-  , sourceHash      :: Maybe String -- ^ The expected hash of the source, if available.
-  } deriving (Show, Eq, Ord)
-
--- | A source for a derivation. It always needs a hash and also has a protocol attached to it (url, git, svn, ...).
--- A @DerivationSource@ also always has it's revision fully resolved (not relative revisions like @master@, @HEAD@, etc).
-data DerivationSource = DerivationSource
-  { derivKind     :: String -- ^ The kind of the source. The name of the build-support fetch derivation should be fetch<kind>.
-  , derivUrl      :: String -- ^ URL to fetch from.
-  , derivRevision :: String -- ^ Revision to use. Leave empty if the fetcher doesn't support revisions.
-  , derivHash     :: String -- ^ The hash of the source.
-  } deriving (Show, Eq, Ord)
-
-instance NFData DerivationSource where
-  rnf (DerivationSource a b c d) = a `deepseq` b `deepseq` c `deepseq` d `deepseq` ()
-
-fromDerivationSource :: DerivationSource -> Source
-fromDerivationSource DerivationSource{..} = Source derivUrl derivRevision $ Just derivHash
-
--- | Fetch a source, trying any of the various nix-prefetch-* scripts.
-fetch :: forall a. (String -> MaybeT IO a)      -- ^ This function is passed the output path name as an argument.
-                                                -- It should return 'Nothing' if the file doesn't match the expected format.
-                                                -- This is required, because we cannot always check if a download succeeded otherwise.
-      -> Source                                 -- ^ The source to fetch from.
-      -> IO (Maybe (DerivationSource, a))       -- ^ The derivation source and the result of the processing function. Returns Nothing if the download failed.
-fetch f = runMaybeT . fetchers where
-  fetchers :: Source -> MaybeT IO (DerivationSource, a)
-  fetchers source = msum . (fetchLocal source :) $ map (\fetcher -> fetchWith fetcher source >>= process)
-    [ (False, "zip", [])
-    , (False, "url", [])
-    , (True, "git", ["--fetch-submodules"])
-    , (True, "hg", [])
-    , (True, "svn", [])
-    , (True, "bzr", [])
-    ]
-
-  -- | Remove '/' from the end of the path. Nix doesn't accept paths that
-  -- end in a slash.
-  stripSlashSuffix :: String -> String
-  stripSlashSuffix = reverse . dropWhile (== '/') . reverse
-
-  fetchLocal :: Source -> MaybeT IO (DerivationSource, a)
-  fetchLocal src = do
-    let path = stripSlashSuffix $ stripPrefix "file://" $ sourceUrl src
-    existsFile <- liftIO $ doesFileExist path
-    existsDir  <- liftIO $ doesDirectoryExist path
-    guard $ existsDir || existsFile
-    let path' | '/' `elem` path = path
-              | otherwise       = "./" ++ path
-    process (DerivationSource "" path' "" "", path') <|> localArchive path'
-
-  localArchive :: FilePath -> MaybeT IO (DerivationSource, a)
-  localArchive path = do
-    absolutePath <- liftIO $ canonicalizePath path
-    unpacked <- snd <$> fetchWith (False, "zip", []) (Source ("file://" ++ absolutePath) "" Nothing)
-    process (DerivationSource "" absolutePath "" "", unpacked)
-
-  process :: (DerivationSource, FilePath) -> MaybeT IO (DerivationSource, a)
-  process (derivSource, file) = (,) derivSource <$> f file
-
--- | Like 'fetch', but allows to specify which script to use.
-fetchWith :: (Bool, String, [String]) -> Source -> MaybeT IO (DerivationSource, FilePath)
-fetchWith (supportsRev, kind, addArgs) source = do
-  unless ((sourceRevision source /= "") || isNothing (sourceHash source) || not supportsRev) $
-    liftIO (hPutStrLn stderr "** need a revision for VCS when the hash is given. skipping.") >> mzero
-
-  MaybeT $ liftIO $ do
-    envs <- getEnvironment
-    (Nothing, Just stdoutH, _, processH) <- createProcess (proc script args)
-      { env = Just $ ("PRINT_PATH", "1") : envs
-      , std_in = Inherit
-      , std_err = Inherit
-      , std_out = CreatePipe
-      }
-
-    exitCode <- waitForProcess processH
-    case exitCode of
-      ExitSuccess   -> fmap Just . processOutputSwitch . lines =<< hGetContents stdoutH
-      ExitFailure _ -> return Nothing
-
- where
-
-   script :: String
-   script = "nix-prefetch-" ++ kind
-
-   args :: [String]
-   args = addArgs ++ sourceUrl source : [ sourceRevision source | supportsRev ] ++ maybeToList (sourceHash source)
-
-   processOutputWithRev :: [String] -> IO (DerivationSource, FilePath)
-   processOutputWithRev [rev,hash,path] = return (DerivationSource kind (sourceUrl source) (extractRevision rev) hash, path)
-   processOutputWithRev out = unexpectedOutput out
-
-   extractRevision :: String -> String
-   extractRevision = unwords . drop 3 . words -- drop the "<vcs> revision is" prefix
-
-   processOutput :: [String] -> IO (DerivationSource, FilePath)
-   processOutput [hash,path] = return (DerivationSource kind (sourceUrl source) (sourceRevision source) hash, path)
-   processOutput out = unexpectedOutput out
-
-   unexpectedOutput :: [String] -> IO a
-   unexpectedOutput out = do
-     hPutStrLn stderr $ "*** unexpected output from " ++ "nix-prefetch-" ++ kind ++ " script: "
-     hPutStr   stderr $ unlines out
-     exitFailure
-
-   processOutputSwitch :: [String] -> IO (DerivationSource, FilePath)
-   processOutputSwitch
-     | supportsRev && isNothing (sourceHash source) = processOutputWithRev
-     | otherwise                                   = processOutput
-
-stripPrefix :: Eq a => [a] -> [a] -> [a]
-stripPrefix prefix as
-  | prefix' == prefix = stripped
-  | otherwise = as
- where
-  (prefix', stripped) = splitAt (length prefix) as
diff --git a/src/Distribution/NixOS/PrettyPrinting.hs b/src/Distribution/NixOS/PrettyPrinting.hs
deleted file mode 100644
--- a/src/Distribution/NixOS/PrettyPrinting.hs
+++ /dev/null
@@ -1,56 +0,0 @@
-{- |
-   Module      :  Distribution.NixOS.PrettyPrinting
-   License     :  BSD3
-
-   Maintainer  :  nix-dev@cs.uu.nl
-   Stability   :  provisional
-   Portability :  portable
-
-   Internal pretty-printing helpers for Nix expressions.
--}
-
-module Distribution.NixOS.PrettyPrinting
-  ( onlyIf
-  , listattr
-  , boolattr
-  , attr
-  , string
-  , funargs
-  , module Text.PrettyPrint
-  )
-  where
-
-import Text.PrettyPrint
-
-attr :: String -> Doc -> Doc
-attr n v = text n <+> equals <+> v <> semi
-
-onlyIf :: [a] -> Doc -> Doc
-onlyIf p d = if not (null p) then d else empty
-
-boolattr :: String -> Bool -> Bool -> Doc
-boolattr n p v = if p then attr n (bool v) else empty
-
-listattr :: String -> Doc -> [String] -> Doc
-listattr n prefix vs = onlyIf vs $
-                sep [ text n <+> equals <+> prefix <+> lbrack,
-                      nest 2 $ fsep $ map text vs,
-                      rbrack <> semi
-                    ]
-
-bool :: Bool -> Doc
-bool True  = text "true"
-bool False = text "false"
-
-string :: String -> Doc
-string = doubleQuotes . text
-
-prepunctuate :: Doc -> [Doc] -> [Doc]
-prepunctuate _ []     = []
-prepunctuate p (d:ds) = d : map (p <>) ds
-
-funargs :: [Doc] -> Doc
-funargs xs = sep [
-               lbrace <+> fcat (prepunctuate (comma <> text " ") $ map (nest 2) xs),
-               rbrace <> colon
-             ]
diff --git a/src/Distribution/NixOS/Regex.hs b/src/Distribution/NixOS/Regex.hs
deleted file mode 100644
--- a/src/Distribution/NixOS/Regex.hs
+++ /dev/null
@@ -1,25 +0,0 @@
-{-# LANGUAGE PatternGuards, CPP #-}
-{- |
-   Module      :  Distribution.NixOS.Derivation.Cabal
-   License     :  BSD3
-
-   Maintainer  :  nix-dev@cs.uu.nl
-   Stability   :  provisional
-   Portability :  PatternGuards
-
-   A represtation of Nix expressions based on Cabal builder defined in
-   @pkgs\/development\/libraries\/haskell\/cabal\/cabal.nix@.
--}
-
-module Distribution.NixOS.Regex
-  ( module Text.Regex.Posix
-  , regsubmatch
-  )
-  where
-
-import Text.Regex.Posix
-
-regsubmatch :: String -> String -> [String]
-regsubmatch buf patt = let (_,_,_,x) = f in x
-  where f :: (String,String,String,[String])
-        f = match (makeRegexOpts compExtended execBlank patt) buf
diff --git a/src/Distribution/Nixpkgs/Fetch.hs b/src/Distribution/Nixpkgs/Fetch.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Fetch.hs
@@ -0,0 +1,155 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE DeriveGeneric #-}
+
+module Distribution.Nixpkgs.Fetch
+  ( Source(..)
+  , Hash(..)
+  , DerivationSource(..), fromDerivationSource
+  , fetch
+  , fetchWith
+  ) where
+
+import Control.Applicative
+import Control.DeepSeq
+import Control.Monad
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Maybe
+import Data.Aeson
+import qualified Data.ByteString.Lazy.Char8 as BS
+import GHC.Generics ( Generic )
+import System.Directory
+import System.Environment
+import System.Exit
+import System.IO
+import System.Process
+
+-- | A source is a location from which we can fetch, such as a HTTP URL, a GIT URL, ....
+data Source = Source
+  { sourceUrl       :: String       -- ^ URL to fetch from.
+  , sourceRevision  :: String       -- ^ Revision to use. For protocols where this doesn't make sense (such as HTTP), this
+                                    --   should be the empty string.
+  , sourceHash      :: Hash         -- ^ The expected hash of the source, if available.
+  } deriving (Show, Eq, Ord, Generic)
+
+instance NFData Source
+
+data Hash = Certain String | Guess String | UnknownHash
+  deriving (Show, Eq, Ord, Generic)
+
+instance NFData Hash
+
+isUnknown :: Hash -> Bool
+isUnknown UnknownHash = True
+isUnknown _           = False
+
+hashToList :: Hash -> [String]
+hashToList (Certain s) = [s]
+hashToList _           = []
+
+-- | A source for a derivation. It always needs a hash and also has a protocol attached to it (url, git, svn, ...).
+-- A @DerivationSource@ also always has it's revision fully resolved (not relative revisions like @master@, @HEAD@, etc).
+data DerivationSource = DerivationSource
+  { derivKind     :: String -- ^ The kind of the source. The name of the build-support fetch derivation should be fetch<kind>.
+  , derivUrl      :: String -- ^ URL to fetch from.
+  , derivRevision :: String -- ^ Revision to use. Leave empty if the fetcher doesn't support revisions.
+  , derivHash     :: String -- ^ The hash of the source.
+  }
+  deriving (Show, Eq, Ord, Generic)
+
+instance NFData DerivationSource
+
+instance FromJSON DerivationSource where
+  parseJSON (Object o) = DerivationSource (error "undefined DerivationSource.kind")
+        <$> o .: "url"
+        <*> o .: "rev"
+        <*> o .: "sha256"
+  parseJSON _ = error "invalid DerivationSource"
+
+fromDerivationSource :: DerivationSource -> Source
+fromDerivationSource DerivationSource{..} = Source derivUrl derivRevision $ Certain derivHash
+
+-- | Fetch a source, trying any of the various nix-prefetch-* scripts.
+fetch :: forall a. (String -> MaybeT IO a)      -- ^ This function is passed the output path name as an argument.
+                                                -- It should return 'Nothing' if the file doesn't match the expected format.
+                                                -- This is required, because we cannot always check if a download succeeded otherwise.
+      -> Source                                 -- ^ The source to fetch from.
+      -> IO (Maybe (DerivationSource, a))       -- ^ The derivation source and the result of the processing function. Returns Nothing if the download failed.
+fetch f = runMaybeT . fetchers where
+  fetchers :: Source -> MaybeT IO (DerivationSource, a)
+  fetchers source = msum . (fetchLocal source :) $ map (\fetcher -> fetchWith fetcher source >>= process)
+    [ (False, "zip", [])
+    , (False, "url", [])
+    , (True, "git", ["--fetch-submodules"])
+    , (True, "hg", [])
+    , (True, "svn", [])
+    , (True, "bzr", [])
+    ]
+
+  -- | Remove '/' from the end of the path. Nix doesn't accept paths that
+  -- end in a slash.
+  stripSlashSuffix :: String -> String
+  stripSlashSuffix = reverse . dropWhile (== '/') . reverse
+
+  fetchLocal :: Source -> MaybeT IO (DerivationSource, a)
+  fetchLocal src = do
+    let path = stripSlashSuffix $ stripPrefix "file://" $ sourceUrl src
+    existsFile <- liftIO $ doesFileExist path
+    existsDir  <- liftIO $ doesDirectoryExist path
+    guard $ existsDir || existsFile
+    let path' | '/' `elem` path = path
+              | otherwise       = "./" ++ path
+    process (DerivationSource "" path' "" "", path') <|> localArchive path'
+
+  localArchive :: FilePath -> MaybeT IO (DerivationSource, a)
+  localArchive path = do
+    absolutePath <- liftIO $ canonicalizePath path
+    unpacked <- snd <$> fetchWith (False, "zip", []) (Source ("file://" ++ absolutePath) "" UnknownHash)
+    process (DerivationSource "" absolutePath "" "", unpacked)
+
+  process :: (DerivationSource, FilePath) -> MaybeT IO (DerivationSource, a)
+  process (derivSource, file) = (,) derivSource <$> f file
+
+-- | Like 'fetch', but allows to specify which script to use.
+fetchWith :: (Bool, String, [String]) -> Source -> MaybeT IO (DerivationSource, FilePath)
+fetchWith (supportsRev, kind, addArgs) source = do
+  unless ((sourceRevision source /= "") || isUnknown (sourceHash source) || not supportsRev) $
+    liftIO (hPutStrLn stderr "** need a revision for VCS when the hash is given. skipping.") >> mzero
+
+  MaybeT $ liftIO $ do
+    envs <- getEnvironment
+    (Nothing, Just stdoutH, _, processH) <- createProcess (proc script args)
+      { env = Just $ ("PRINT_PATH", "1") : envs
+      , std_in = Inherit
+      , std_err = Inherit
+      , std_out = CreatePipe
+      }
+
+    exitCode <- waitForProcess processH
+    case exitCode of
+      ExitFailure _ -> return Nothing
+      ExitSuccess   -> do
+        buf <- BS.hGetContents stdoutH
+        let (l:ls) = reverse (BS.lines buf)
+            buf'   = BS.unlines (reverse ls)
+        case length ls of
+          0 -> return Nothing
+          1 -> return (Just (DerivationSource kind (sourceUrl source) "" (BS.unpack (head ls))  , sourceUrl source))
+          _ -> case eitherDecode buf' of
+                 Left err -> error ("invalid JSON: " ++ err ++ " in " ++ show buf')
+                 Right ds -> return (Just (ds { derivKind = kind }, BS.unpack l))
+ where
+
+   script :: String
+   script = "nix-prefetch-" ++ kind
+
+   args :: [String]
+   args = addArgs ++ sourceUrl source : [ sourceRevision source | supportsRev ] ++ hashToList (sourceHash source)
+
+stripPrefix :: Eq a => [a] -> [a] -> [a]
+stripPrefix prefix as
+  | prefix' == prefix = stripped
+  | otherwise = as
+ where
+  (prefix', stripped) = splitAt (length prefix) as
diff --git a/src/Distribution/Nixpkgs/Haskell.hs b/src/Distribution/Nixpkgs/Haskell.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell.hs
@@ -0,0 +1,8 @@
+module Distribution.Nixpkgs.Haskell
+  ( module Distribution.Nixpkgs.Haskell.BuildInfo
+  , module Distribution.Nixpkgs.Haskell.Derivation
+  )
+  where
+
+import Distribution.Nixpkgs.Haskell.BuildInfo
+import Distribution.Nixpkgs.Haskell.Derivation
diff --git a/src/Distribution/Nixpkgs/Haskell/BuildInfo.hs b/src/Distribution/Nixpkgs/Haskell/BuildInfo.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/BuildInfo.hs
@@ -0,0 +1,45 @@
+{-# LANGUAGE DeriveGeneric         #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TemplateHaskell       #-}
+
+module Distribution.Nixpkgs.Haskell.BuildInfo
+  ( BuildInfo
+  , haskell, pkgconfig, system, tool, pPrintBuildInfo
+  )
+  where
+
+import Control.DeepSeq
+import Control.Lens
+import Data.Set ( Set )
+import Data.Set.Lens
+import GHC.Generics ( Generic )
+import Language.Nix
+import Language.Nix.PrettyPrinting
+
+data BuildInfo = BuildInfo
+  { _haskell   :: Set Binding
+  , _pkgconfig :: Set Binding
+  , _system    :: Set Binding
+  , _tool      :: Set Binding
+  }
+  deriving (Show, Eq, Generic)
+
+makeLenses ''BuildInfo
+
+instance Each BuildInfo BuildInfo (Set Binding) (Set Binding) where
+  each f (BuildInfo a b c d) = BuildInfo <$> f a <*> f b <*> f c <*> f d
+
+instance Monoid BuildInfo where
+  mempty = BuildInfo mempty mempty mempty mempty
+  BuildInfo w1 x1 y1 z1 `mappend` BuildInfo w2 x2 y2 z2 = BuildInfo (w1 `mappend` w2) (x1 `mappend` x2) (y1 `mappend` y2) (z1 `mappend` z2)
+
+instance NFData BuildInfo
+
+pPrintBuildInfo :: String -> BuildInfo -> Doc
+pPrintBuildInfo prefix bi = vcat
+  [ setattr (prefix++"HaskellDepends") empty (setOf (haskell.folded.localName.ident) bi)
+  , setattr (prefix++"SystemDepends")  empty (setOf (system.folded.localName.ident) bi)
+  , setattr (prefix++"PkgconfigDepends") empty (setOf (pkgconfig.folded.localName.ident) bi)
+  , setattr (prefix++"ToolDepends") empty (setOf (tool.folded.localName.ident) bi)
+  ]
diff --git a/src/Distribution/Nixpkgs/Haskell/Constraint.hs b/src/Distribution/Nixpkgs/Haskell/Constraint.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/Constraint.hs
@@ -0,0 +1,15 @@
+module Distribution.Nixpkgs.Haskell.Constraint
+  ( Constraint, satisfiesConstraint, satisfiesConstraints
+  ) where
+
+import Distribution.Package
+import Distribution.Version
+import Distribution.Nixpkgs.Haskell.OrphanInstances ( )
+
+type Constraint = Dependency
+
+satisfiesConstraint :: PackageIdentifier -> Constraint -> Bool
+satisfiesConstraint (PackageIdentifier pn v) (Dependency cn vr) = (pn /= cn) || (v `withinRange` vr)
+
+satisfiesConstraints :: PackageIdentifier -> [Constraint] -> Bool
+satisfiesConstraints p = all (satisfiesConstraint p)
diff --git a/src/Distribution/Nixpkgs/Haskell/Derivation.hs b/src/Distribution/Nixpkgs/Haskell/Derivation.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/Derivation.hs
@@ -0,0 +1,148 @@
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
+
+module Distribution.Nixpkgs.Haskell.Derivation
+  ( Derivation, nullDerivation, pkgid, revision, src, isLibrary, isExecutable
+  , extraFunctionArgs, libraryDepends, executableDepends, testDepends, configureFlags
+  , cabalFlags, runHaddock, jailbreak, doCheck, testTarget, hyperlinkSource, enableSplitObjs
+  , enableLibraryProfiling, enableExecutableProfiling, phaseOverrides, editedCabalFile, metaSection
+  , dependencies, setupDepends
+  )
+  where
+
+import Control.DeepSeq
+import Control.Lens
+import Data.List
+import Data.Set ( Set )
+import qualified Data.Set as Set
+import Data.Set.Lens
+import Distribution.Nixpkgs.Fetch
+import Distribution.Nixpkgs.Haskell.BuildInfo
+import Distribution.Nixpkgs.Haskell.OrphanInstances ( )
+import Distribution.Nixpkgs.Meta
+import Distribution.Package
+import Distribution.PackageDescription ( FlagAssignment, FlagName(..) )
+import GHC.Generics ( Generic )
+import Language.Nix
+import Language.Nix.PrettyPrinting
+
+-- | A represtation of Nix expressions for building Haskell packages.
+-- The data type correspond closely to the definition of
+-- 'PackageDescription' from Cabal.
+
+data Derivation = MkDerivation
+  { _pkgid                      :: PackageIdentifier
+  , _revision                   :: Int
+  , _src                        :: DerivationSource
+  , _isLibrary                  :: Bool
+  , _isExecutable               :: Bool
+  , _extraFunctionArgs          :: Set Identifier
+  , _setupDepends               :: BuildInfo
+  , _libraryDepends             :: BuildInfo
+  , _executableDepends          :: BuildInfo
+  , _testDepends                :: BuildInfo
+  , _configureFlags             :: Set String
+  , _cabalFlags                 :: FlagAssignment
+  , _runHaddock                 :: Bool
+  , _jailbreak                  :: Bool
+  , _doCheck                    :: Bool
+  , _testTarget                 :: String
+  , _hyperlinkSource            :: Bool
+  , _enableLibraryProfiling     :: Bool
+  , _enableExecutableProfiling  :: Bool
+  , _enableSplitObjs            :: Bool
+  , _phaseOverrides             :: String
+  , _editedCabalFile            :: String
+  , _metaSection                :: Meta
+  }
+  deriving (Show, Eq, Generic)
+
+nullDerivation :: Derivation
+nullDerivation = MkDerivation
+  { _pkgid = error "undefined Derivation.pkgid"
+  , _revision = error "undefined Derivation.revision"
+  , _src = error "undefined Derivation.src"
+  , _isLibrary = error "undefined Derivation.isLibrary"
+  , _isExecutable = error "undefined Derivation.isExecutable"
+  , _extraFunctionArgs = error "undefined Derivation.extraFunctionArgs"
+  , _setupDepends = error "undefined Derivation.setupDepends"
+  , _libraryDepends = error "undefined Derivation.libraryDepends"
+  , _executableDepends = error "undefined Derivation.executableDepends"
+  , _testDepends = error "undefined Derivation.testDepends"
+  , _configureFlags = error "undefined Derivation.configureFlags"
+  , _cabalFlags = error "undefined Derivation.cabalFlags"
+  , _runHaddock = error "undefined Derivation.runHaddock"
+  , _jailbreak = error "undefined Derivation.jailbreak"
+  , _doCheck = error "undefined Derivation.doCheck"
+  , _testTarget = error "undefined Derivation.testTarget"
+  , _hyperlinkSource = error "undefined Derivation.hyperlinkSource"
+  , _enableLibraryProfiling = error "undefined Derivation.enableLibraryProfiling"
+  , _enableExecutableProfiling = error "undefined Derivation.enableExecutableProfiling"
+  , _enableSplitObjs = error "undefined Derivation.enableSplitObjs"
+  , _phaseOverrides = error "undefined Derivation.phaseOverrides"
+  , _editedCabalFile = error "undefined Derivation.editedCabalFile"
+  , _metaSection = error "undefined Derivation.metaSection"
+  }
+
+makeLenses ''Derivation
+
+makeLensesFor [("_setupDepends", "dependencies"), ("_libraryDepends", "dependencies"), ("_executableDepends", "dependencies"), ("_testDepends", "dependencies")] ''Derivation
+
+instance Package Derivation where
+  packageId = view pkgid
+
+instance NFData Derivation
+
+instance Pretty Derivation where
+  pPrint drv@(MkDerivation {..}) = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat
+    [ text "mkDerivation" <+> lbrace
+    , nest 2 $ vcat
+      [ attr "pname"   $ doubleQuotes $ disp (packageName _pkgid)
+      , attr "version" $ doubleQuotes $ disp (packageVersion _pkgid)
+      , sourceAttr _src
+      , onlyIf (_revision > 0) $ attr "revision" $ doubleQuotes $ int _revision
+      , onlyIf (not (null _editedCabalFile) && _revision > 0) $ attr "editedCabalFile" $ string _editedCabalFile
+      , listattr "configureFlags" empty (map (show . show) renderedFlags)
+      , boolattr "isLibrary" (not _isLibrary || _isExecutable) _isLibrary
+      , boolattr "isExecutable" (not _isLibrary || _isExecutable) _isExecutable
+      , onlyIf (_setupDepends /= mempty) $ pPrintBuildInfo "setup" _setupDepends
+      , onlyIf (_libraryDepends /= mempty) $ pPrintBuildInfo "library" _libraryDepends
+      , onlyIf (_executableDepends /= mempty) $ pPrintBuildInfo "executable" _executableDepends
+      , onlyIf (_testDepends /= mempty) $ pPrintBuildInfo "test" _testDepends
+      , boolattr "enableLibraryProfiling" _enableLibraryProfiling _enableLibraryProfiling
+      , boolattr "enableExecutableProfiling" _enableExecutableProfiling _enableExecutableProfiling
+      , boolattr "enableSplitObjs"  (not _enableSplitObjs) _enableSplitObjs
+      , boolattr "doHaddock" (not _runHaddock) _runHaddock
+      , boolattr "jailbreak" _jailbreak _jailbreak
+      , boolattr "doCheck" (not _doCheck) _doCheck
+      , onlyIf (not (null _testTarget)) $ attr "testTarget" $ string _testTarget
+      , boolattr "hyperlinkSource" (not _hyperlinkSource) _hyperlinkSource
+      , onlyIf (not (null _phaseOverrides)) $ vcat ((map text . lines) _phaseOverrides)
+      , pPrint _metaSection
+      ]
+    , rbrace
+    ]
+    where
+      inputs :: Set String
+      inputs = Set.unions [ Set.map (view ident) _extraFunctionArgs
+                          , setOf (dependencies . each . folded . localName . ident) drv
+                          , Set.fromList ["fetch" ++ derivKind _src | derivKind _src /= "" && not isHackagePackage]
+                          ]
+
+      renderedFlags = [ text "-f" <> (if enable then empty else char '-') <> text f | (FlagName f, enable) <- _cabalFlags ]
+                      ++ map text (toAscList _configureFlags)
+      isHackagePackage = "mirror://hackage/" `isPrefixOf` derivUrl _src
+      sourceAttr (DerivationSource{..})
+        | isHackagePackage = attr "sha256" $ string derivHash
+        | derivKind /= "" = vcat
+           [ text "src" <+> equals <+> text ("fetch" ++ derivKind) <+> lbrace
+           , nest 2 $ vcat
+             [ attr "url" $ string derivUrl
+             , attr "sha256" $ string derivHash
+             , if derivRevision /= "" then attr "rev" (string derivRevision) else empty
+             ]
+           , rbrace <> semi
+           ]
+        | otherwise = attr "src" $ text derivUrl
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal.hs
@@ -0,0 +1,138 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+
+module Distribution.Nixpkgs.Haskell.FromCabal
+  ( HaskellResolver, NixpkgsResolver
+  , fromGenericPackageDescription , fromPackageDescription
+  )
+  where
+
+import Control.Arrow ( second )
+import Control.Lens
+import Data.Maybe
+import Data.Set ( Set )
+import qualified Data.Set as Set
+import Distribution.Compiler
+import Distribution.Nixpkgs.Haskell
+import qualified Distribution.Nixpkgs.Haskell as Nix
+import Distribution.Nixpkgs.Haskell.Constraint
+import Distribution.Nixpkgs.Haskell.FromCabal.License
+import Distribution.Nixpkgs.Haskell.FromCabal.Name
+import Distribution.Nixpkgs.Haskell.FromCabal.Normalize
+import Distribution.Nixpkgs.Haskell.FromCabal.PostProcess
+import qualified Distribution.Nixpkgs.Meta as Nix
+import Distribution.Package
+import Distribution.PackageDescription
+import qualified Distribution.PackageDescription as Cabal
+import Distribution.PackageDescription.Configuration
+import Distribution.System
+import Distribution.Text ( display )
+import Distribution.Version
+import Language.Nix
+
+type HaskellResolver = Dependency -> Bool
+type NixpkgsResolver = Identifier -> Maybe Binding
+
+fromGenericPackageDescription :: HaskellResolver -> NixpkgsResolver -> Platform -> CompilerInfo ->  FlagAssignment -> [Constraint] -> GenericPackageDescription -> Derivation
+fromGenericPackageDescription haskellResolver nixpkgsResolver arch compiler flags constraints descr'' =
+  -- TODO: This logic needs simplification and cleanup. :-(
+  case finalize haskellResolver of
+    Left _ -> case finalize jailbrokenResolver of
+                Left missing -> case finalize (const True) of
+                                  Left missing' -> error $ "finalizePackageDescription complains about missing dependencies \
+                                                           \even though we told it that everything exists: " ++ show missing'
+                                  Right (descr_,_) -> fromPackageDescription haskellResolver nixpkgsResolver True missing flags descr_
+                Right _      -> fromPackageDescription haskellResolver nixpkgsResolver True [] flags descr
+    Right _ -> fromPackageDescription haskellResolver nixpkgsResolver False [] flags descr
+  where
+    descr :: PackageDescription
+    Right (descr,_) = finalize jailbrokenResolver
+
+    -- We have to call the Cabal finalizer several times with different resolver functions, and this
+    -- convenience function makes our code shorter.
+    finalize :: HaskellResolver -> Either [Dependency] (PackageDescription,FlagAssignment)
+    finalize resolver = finalizePackageDescription flags resolver arch compiler constraints descr'
+
+    jailbrokenResolver :: HaskellResolver
+    jailbrokenResolver (Dependency pkg _) = haskellResolver (Dependency pkg anyVersion)
+
+    -- A variant of the cabal file that has all test suites enabled to ensure
+    -- that their dependencies are recognized by finalizePackageDescription.
+    descr' :: GenericPackageDescription
+    descr' = descr'' { condTestSuites = flaggedTests }
+
+    flaggedTests :: [(String, CondTree ConfVar [Dependency] TestSuite)]
+    flaggedTests = map (second (mapTreeData enableTest)) (condTestSuites descr'')
+
+    enableTest :: TestSuite -> TestSuite
+    enableTest t = t { testEnabled = True }
+
+fromPackageDescription :: HaskellResolver -> NixpkgsResolver -> Bool -> [Dependency] -> FlagAssignment -> PackageDescription -> Derivation
+fromPackageDescription haskellResolver nixpkgsResolver mismatchedDeps missingDeps flags (PackageDescription {..}) = normalize $ postProcess $ nullDerivation
+    & isLibrary .~ isJust library
+    & pkgid .~ package
+    & revision .~ xrev
+    & isLibrary .~ isJust library
+    & isExecutable .~ not (null executables)
+    & extraFunctionArgs .~ mempty
+    & libraryDepends .~ maybe mempty (convertBuildInfo . libBuildInfo) library
+    & executableDepends .~ mconcat (map (convertBuildInfo . buildInfo) executables)
+    & testDepends .~ mconcat (map (convertBuildInfo . testBuildInfo) testSuites)
+    & Nix.setupDepends .~ maybe mempty convertSetupBuildInfo setupBuildInfo
+    & configureFlags .~ mempty
+    & cabalFlags .~ flags
+    & runHaddock .~ maybe True (not . null . exposedModules) library
+    & jailbreak .~ (mismatchedDeps || not (null missingDeps))
+    & doCheck .~ True
+    & testTarget .~ mempty
+    & hyperlinkSource .~ True
+    & enableSplitObjs .~ True
+    & enableLibraryProfiling .~ False
+    & enableExecutableProfiling .~ False
+    & phaseOverrides .~ mempty
+    & editedCabalFile .~ (if xrev > 0
+                             then fromMaybe (error (display package ++ ": X-Cabal-File-Hash field is missing")) (lookup "X-Cabal-File-Hash" customFieldsPD)
+                             else "")
+    & metaSection .~ ( Nix.nullMeta
+                     & Nix.homepage .~ homepage
+                     & Nix.description .~ synopsis
+                     & Nix.license .~ fromCabalLicense license
+                     & Nix.platforms .~ Nix.allKnownPlatforms
+                     & Nix.hydraPlatforms .~ Nix.allKnownPlatforms
+                     & Nix.maintainers .~ mempty
+                     & Nix.broken .~ not (null missingDeps)
+                     )
+  where
+    xrev = maybe 0 read (lookup "x-revision" customFieldsPD)
+
+    resolveInHackage :: Identifier -> Binding
+    resolveInHackage i | (i^.ident) `elem` [ n | (Dependency (PackageName n) _) <- missingDeps ] = bindNull i
+                       | otherwise = binding # (i, path # ["self",i])   -- TODO: "self" shouldn't be hardcoded.
+
+    goodScopes :: Set [Identifier]
+    goodScopes = Set.fromList (map ("pkgs":) [[], ["xorg"], ["xlibs"], ["gnome"], ["gnome3"], ["kde4"]])
+
+    resolveInNixpkgs :: Identifier -> Binding
+    resolveInNixpkgs i
+      | i `elem` ["clang","lldb","llvm"] = binding # (i, path # ["self","llvmPackages",i])     -- TODO: evil!
+      | i `elem` ["gtk2","gtk3"]         = binding # (i, path # ["pkgs","gnome2","gtk"])
+      | Just p <- nixpkgsResolver i, init (view (reference . path) p) `Set.member` goodScopes = p
+      | otherwise                        = bindNull i
+
+    resolveInHackageThenNixpkgs :: Identifier -> Binding
+    resolveInHackageThenNixpkgs i | haskellResolver (Dependency (PackageName (i^.ident)) anyVersion) = resolveInHackage i
+                                  | otherwise = resolveInNixpkgs i
+
+    convertBuildInfo :: Cabal.BuildInfo -> Nix.BuildInfo
+    convertBuildInfo Cabal.BuildInfo {..} = mempty
+      & haskell .~ Set.fromList [ resolveInHackage (toNixName x) | (Dependency x _) <- targetBuildDepends ]
+      & system .~ Set.fromList [ resolveInNixpkgs y | x <- extraLibs, y <- libNixName x ]
+      & pkgconfig .~ Set.fromList [ resolveInNixpkgs y | Dependency (PackageName x) _ <- pkgconfigDepends, y <- libNixName x ]
+      & tool .~ Set.fromList [ resolveInHackageThenNixpkgs y | Dependency (PackageName x) _ <- buildTools, y <- buildToolNixName x ]
+
+    convertSetupBuildInfo :: Cabal.SetupBuildInfo -> Nix.BuildInfo
+    convertSetupBuildInfo bi = mempty
+      & haskell .~ Set.fromList [ resolveInHackage (toNixName x) | (Dependency x _) <- Cabal.setupDepends bi ]
+
+bindNull :: Identifier -> Binding
+bindNull i = binding # (i, path # ["null"])
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal/Configuration.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal/Configuration.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal/Configuration.hs
@@ -0,0 +1,101 @@
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Distribution.Nixpkgs.Haskell.FromCabal.Configuration ( Configuration(..), readConfiguration, assertConsistency ) where
+
+import Control.DeepSeq
+import Control.Lens
+import Control.Monad
+import Data.Map as Map
+import Data.Set as Set
+import Data.Text as T
+import Data.Yaml
+import Distribution.Compiler
+import Distribution.Nixpkgs.Haskell.Constraint
+import Distribution.Package
+import Distribution.System
+import GHC.Generics ( Generic )
+import Language.Nix.Identifier
+
+data Configuration = Configuration
+  {
+  -- |Target compiler. Used by 'finalizePackageDescription' to choose
+  -- appropriate flags and dependencies.
+    compilerInfo :: CompilerInfo
+
+  -- |Compiler core packages that are also found on Hackage.
+  , corePackages :: Set PackageIdentifier
+
+  -- |These packages replace the latest respective version during
+  -- dependency resolution.
+  , defaultPackageOverrides :: [Constraint]
+
+  -- |These packages are added to the generated set, but the play no
+  -- role during dependency resolution.
+  , extraPackages :: [Constraint]
+
+  -- |We know that these packages won't build, so we give them an empty
+  -- meta.hydraPlatforms attribute to avoid cluttering our Hydra output with
+  -- lots of failure messages.
+  , dontDistributePackages :: Map PackageName (Set Platform)
+
+  -- |This information is used by the @hackage2nix@ utility to determine the
+  -- 'maintainers' for a given Haskell package.
+  , packageMaintainers :: Map Identifier (Set PackageName)
+  }
+  deriving (Show, Generic)
+
+instance NFData Configuration
+
+instance FromJSON Configuration where
+  parseJSON (Object o) = Configuration
+        <$> o .:? "compiler" .!= unknownCompilerInfo buildCompilerId NoAbiTag
+        <*> o .:? "core-packages" .!= mempty
+        <*> o .:? "default-package-overrides" .!= mempty
+        <*> o .:? "extra-packages" .!= mempty
+        <*> o .:? "dont-distribute-packages" .!= mempty
+        <*> o .:? "package-maintainers" .!= mempty
+  parseJSON _ = error "invalid Configuration"
+
+instance FromJSON Identifier where
+  parseJSON (String s) = pure (review ident (T.unpack s))
+  parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Nix identifier")
+
+-- aeson-0.11 introduces a general instance, so we just need a couple
+-- of specific ones
+#if MIN_VERSION_aeson(0,11,0)
+instance (FromJSON v) => FromJSON (Map Identifier v) where
+  parseJSON = fmap (Map.mapKeys parseKey) . parseJSON
+
+instance (FromJSON v) => FromJSON (Map PackageName v) where
+  parseJSON = fmap (Map.mapKeys parseKey) . parseJSON
+
+parseKey :: (FromJSON k) => Text -> k
+parseKey s = either error id (parseEither parseJSON (String s))
+#else
+instance (Ord k, FromJSON k, FromJSON v) => FromJSON (Map k v) where
+  parseJSON  = fmap (Map.mapKeys parseKey) . parseJSON
+    where
+      parseKey :: FromJSON k => Text -> k
+      parseKey s = either error id (parseEither parseJSON (String s))
+#endif
+
+readConfiguration :: FilePath -> IO Configuration
+readConfiguration path =
+  decodeFile path >>= maybe (fail ("invalid config file at " ++ show path)) assertConsistency
+
+assertConsistency :: Monad m => Configuration -> m Configuration
+assertConsistency cfg@(Configuration {..}) = do
+  let report msg = fail ("*** configuration error: " ++ msg)
+
+      maintainedPackages = Set.unions (Map.elems packageMaintainers)
+      disabledPackages = Map.keysSet dontDistributePackages
+      disabledMaintainedPackages = maintainedPackages `Set.intersection` disabledPackages
+  unless (Set.null disabledMaintainedPackages) $
+    report ("disabled packages that have a maintainer: " ++ show disabledMaintainedPackages)
+
+  return cfg
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal/Flags.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal/Flags.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal/Flags.hs
@@ -0,0 +1,57 @@
+module Distribution.Nixpkgs.Haskell.FromCabal.Flags ( configureCabalFlags ) where
+
+import Distribution.Package
+import Distribution.PackageDescription
+import Data.Version
+
+configureCabalFlags :: PackageIdentifier -> FlagAssignment
+configureCabalFlags (PackageIdentifier (PackageName name) version)
+ | name == "accelerate-examples"= [disable "opencl"]
+ | name == "arithmoi"           = [disable "llvm"]
+ | name == "darcs"              = [enable "library", enable "force-char8-encoding"]
+ | name == "diagrams-builder"   = [enable "cairo", enable "svg", enable "ps", enable "rasterific"]
+ | name == "folds"              = [disable "test-hlint"]
+ | name == "git-annex"          = [ enable "assistant"
+                                  , enable "cryptonite"
+                                  , enable "dbus"
+                                  , enable "desktopnotify"
+                                  , enable "dns"
+                                  , enable "feed"
+                                  , enable "inotify"
+                                  , enable "pairing"
+                                  , enable "production"
+                                  , enable "quvi"
+                                  , enable "s3"
+                                  , enable "tahoe"
+                                  , enable "tdfa"
+                                  , enable "testsuite"
+                                  , enable "torrentparser"
+                                  , enable "webapp"
+                                  , enable "webapp-secure"
+                                  , enable "webdav"
+                                  , enable "xmpp"
+                                  ]
+ | name == "haskeline"          = [enable "terminfo"]
+ | name == "haste-compiler"     = [enable "portable"]
+ | name == "highlighting-kate"  = [enable "pcre-light"]
+ | name == "hlibsass" && version >= Version [0,1,5] []
+                                = [enable "externalLibsass"]
+ | name == "hmatrix"            = [enable "openblas"]
+ | name == "hslua"              = [enable "system-lua"]
+ | name == "idris"              = [enable "gmp", enable "ffi", enable "curses"]
+ | name == "io-streams"         = [enable "NoInteractiveTests"]
+ | name == "liquid-fixpoint"    = [enable "build-external"]
+ | name == "pandoc"             = [enable "https", disable "trypandoc"]
+ | name == "reactive-banana-wx" = [disable "buildExamples"]
+ | name == "snap-server"        = [enable "openssl"]
+ | name == "xmobar"             = [enable "all_extensions"]
+ | name == "xmonad-extras"      = [disable "with_hlist", enable "with_split", enable "with_parsec"]
+ | name == "yaml"               = [enable "system-libyaml"]
+ | name == "yi"                 = [enable "pango", enable "vty"]
+ | otherwise                    = []
+
+enable :: String -> (FlagName,Bool)
+enable name = (FlagName name, True)
+
+disable :: String -> (FlagName,Bool)
+disable name = (FlagName name, False)
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal/License.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal/License.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal/License.hs
@@ -0,0 +1,30 @@
+module Distribution.Nixpkgs.Haskell.FromCabal.License ( fromCabalLicense ) where
+
+import Distribution.Nixpkgs.License
+import Distribution.License ( License(..) )
+import Data.Version
+
+fromCabalLicense :: Distribution.License.License -> Distribution.Nixpkgs.License.License
+fromCabalLicense (GPL Nothing)                          = Unknown (Just "GPL")
+fromCabalLicense (GPL (Just (Version [2] [])))          = Known "stdenv.lib.licenses.gpl2"
+fromCabalLicense (GPL (Just (Version [3] [])))          = Known "stdenv.lib.licenses.gpl3"
+fromCabalLicense (LGPL Nothing)                         = Unknown (Just "LGPL")
+fromCabalLicense (LGPL (Just (Version [2,1] [])))       = Known "stdenv.lib.licenses.lgpl21"
+fromCabalLicense (LGPL (Just (Version [2] [])))         = Known "stdenv.lib.licenses.lgpl2"
+fromCabalLicense (LGPL (Just (Version [3] [])))         = Known "stdenv.lib.licenses.lgpl3"
+fromCabalLicense (AGPL Nothing)                         = Unknown (Just "AGPL")
+fromCabalLicense (AGPL (Just (Version [3] [])))         = Known "stdenv.lib.licenses.agpl3"
+fromCabalLicense (AGPL (Just (Version [3,0] [])))       = Known "stdenv.lib.licenses.agpl3"
+fromCabalLicense (MPL (Version [2,0] []))               = Known "stdenv.lib.licenses.mpl20"
+fromCabalLicense BSD2                                   = Known "stdenv.lib.licenses.bsd2"
+fromCabalLicense BSD3                                   = Known "stdenv.lib.licenses.bsd3"
+fromCabalLicense BSD4                                   = Known "stdenv.lib.licenses.bsdOriginal"
+fromCabalLicense MIT                                    = Known "stdenv.lib.licenses.mit"
+fromCabalLicense PublicDomain                           = Known "stdenv.lib.licenses.publicDomain"
+fromCabalLicense UnspecifiedLicense                     = Known "stdenv.lib.licenses.unfree"
+fromCabalLicense AllRightsReserved                      = Known "stdenv.lib.licenses.unfree"
+fromCabalLicense (Apache Nothing)                       = Known "stdenv.lib.licenses.asl20"
+fromCabalLicense (Apache (Just (Version [2,0] [])))     = Known "stdenv.lib.licenses.asl20"
+fromCabalLicense ISC                                    = Known "stdenv.lib.licenses.isc"
+fromCabalLicense OtherLicense                           = Unknown Nothing
+fromCabalLicense l                                      = error $ "Distribution.Nixpkgs.Haskell.FromCabal.License.fromCabalLicense: unknown license " ++ show l
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs
@@ -0,0 +1,198 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Distribution.Nixpkgs.Haskell.FromCabal.Name ( toNixName, libNixName, buildToolNixName ) where
+
+import Data.String
+import Distribution.Package
+import Language.Nix
+
+-- | Map Cabal names to Nix attribute names.
+toNixName :: PackageName -> Identifier
+toNixName (PackageName "") = error "toNixName: invalid empty package name"
+toNixName (PackageName n)  = fromString n
+
+-- | Map libraries to Nix packages.
+--
+-- TODO: This list should not be hard-coded here; it belongs into the Nixpkgs
+-- repository.
+
+libNixName :: String -> [Identifier]
+libNixName ""                                   = []
+libNixName "adns"                               = return "adns"
+libNixName "alsa"                               = return "alsaLib"
+libNixName "alut"                               = return "freealut"
+libNixName "appindicator-0.1"                   = return "appindicator"
+libNixName "appindicator3-0.1"                  = return "appindicator"
+libNixName "asound"                             = return "alsaLib"
+libNixName "awesomium-1.6.5"                    = return "awesomium"
+libNixName "b2"                                 = return "libb2"
+libNixName "bz2"                                = return "bzip2"
+libNixName "c++"                                = []  -- What is that?
+libNixName "cairo"                              = return "cairo"
+libNixName "cairo-pdf"                          = return "cairo"
+libNixName "cairo-ps"                           = return "cairo"
+libNixName "cairo-svg"                          = return "cairo"
+libNixName "CEGUIBase-0.7.7"                    = return "CEGUIBase"
+libNixName "CEGUIOgreRenderer-0.7.7"            = return "CEGUIOgreRenderer"
+libNixName "clutter-1.0"                        = return "clutter"
+libNixName "crypt"                              = []  -- provided by glibc
+libNixName "crypto"                             = return "openssl"
+libNixName "curses"                             = return "ncurses"
+libNixName "dl"                                 = []  -- provided by glibc
+libNixName "fftw3"                              = return "fftw"
+libNixName "fftw3f"                             = return "fftwFloat"
+libNixName "gconf"                              = return "GConf"
+libNixName "gconf-2.0"                          = return "GConf"
+libNixName "gdk-2.0"                            = return "gdk2"
+libNixName "gdk-3.0"                            = return "gdk3"
+libNixName "gdk-pixbuf-2.0"                     = return "gdk_pixbuf"
+libNixName "gdk-x11-2.0"                        = return "gdk_x11"
+libNixName "gio-2.0"                            = return "glib"
+libNixName "GL"                                 = return "mesa"
+libNixName "glib-2.0"                           = return "glib"
+libNixName "GLU"                                = ["freeglut","mesa"]
+libNixName "glut"                               = ["freeglut","mesa"]
+libNixName "gmime-2.4"                          = return "gmime"
+libNixName "gnome-keyring"                      = return "gnome_keyring"
+libNixName "gnome-keyring-1"                    = return "gnome_keyring"
+libNixName "gnome-vfs-2.0"                      = return "gnome_vfs"
+libNixName "gnome-vfs-module-2.0"               = return "gnome_vfs_module"
+libNixName "gobject-2.0"                        = return "glib"
+libNixName "gobject-introspection-1.0"          = return "gobjectIntrospection"
+libNixName "gstreamer-0.10"                     = return "gstreamer"
+libNixName "gstreamer-1.0"                      = return "gstreamer"
+libNixName "gstreamer-audio-0.10"               = return "gst_plugins_base"
+libNixName "gstreamer-audio-1.0"                = return "gst_plugins_base"
+libNixName "gstreamer-base-0.10"                = return "gst_plugins_base"
+libNixName "gstreamer-base-1.0"                 = return "gst_plugins_base"
+libNixName "gstreamer-controller-0.10"          = return "gstreamer"
+libNixName "gstreamer-dataprotocol-0.10"        = return "gstreamer"
+libNixName "gstreamer-net-0.10"                 = return "gst_plugins_base"
+libNixName "gstreamer-plugins-base-0.10"        = return "gst_plugins_base"
+libNixName "gstreamer-video-1.0"                = return "gst_plugins_base"
+libNixName "gthread-2.0"                        = return "glib"
+libNixName "gtk+-2.0"                           = return "gtk2"
+libNixName "gtk+-3.0"                           = return "gtk3"
+libNixName "gtk-x11-2.0"                        = return "gtk_x11"
+libNixName "gtkglext-1.0"                       = return "gtkglext"
+libNixName "gtksourceview-2.0"                  = return "gtksourceview"
+libNixName "gtksourceview-3.0"                  = return "gtksourceview"
+libNixName "hidapi-libusb"                      = return "hidapi"
+libNixName "icudata"                            = return "icu"
+libNixName "icui18n"                            = return "icu"
+libNixName "icuuc"                              = return "icu"
+libNixName "idn"                                = return "libidn"
+libNixName "IL"                                 = return "libdevil"
+libNixName "ImageMagick"                        = return "imagemagick"
+libNixName "Imlib2"                             = return "imlib2"
+libNixName "iw"                                 = return "wirelesstools"
+libNixName "jack"                               = return "libjack2"
+libNixName "javascriptcoregtk-3.0"              = return "javascriptcoregtk"
+libNixName "javascriptcoregtk-4.0"              = return "javascriptcoregtk"
+libNixName "jpeg"                               = return "libjpeg"
+libNixName "lapack"                             = return "liblapack"
+libNixName "ldap"                               = return "openldap"
+libNixName "libavutil"                          = return "ffmpeg"
+libNixName "libglade-2.0"                       = return "libglade"
+libNixName "libgsasl"                           = return "gsasl"
+libNixName "libpcre"                            = return "pcre"
+libNixName "libR"                               = return "R"
+libNixName "librsvg-2.0"                        = return "librsvg"
+libNixName "libsoup-2.4"                        = return "libsoup"
+libNixName "libsoup-gnome-2.4"                  = return "libsoup"
+libNixName "libsystemd"                         = return "systemd"
+libNixName "libusb-1.0"                         = return "libusb"
+libNixName "libxml-2.0"                         = return "libxml2"
+libNixName "libzip"                             = return "libzip"
+libNixName "libzmq"                             = return "zeromq"
+libNixName "m"                                  = []  -- in stdenv
+libNixName "magic"                              = return "file"
+libNixName "MagickWand"                         = return "imagemagick"
+libNixName "mono-2.0"                           = return "mono"
+libNixName "mpi"                                = return "openmpi"
+libNixName "ncursesw"                           = return "ncurses"
+libNixName "netsnmp"                            = return "net_snmp"
+libNixName "notify"                             = return "libnotify"
+libNixName "odbc"                               = return "unixODBC"
+libNixName "openblas"                           = return "openblasCompat"
+libNixName "panelw"                             = return "ncurses"
+libNixName "pangocairo"                         = return "pango"
+libNixName "pcap"                               = return "libpcap"
+libNixName "pfs-1.2"                            = return "pfstools"
+libNixName "png"                                = return "libpng"
+libNixName "poppler-glib"                       = return "poppler"
+libNixName "portaudio-2.0"                      = return "portaudio"
+libNixName "pq"                                 = return "postgresql"
+libNixName "pthread"                            = []
+libNixName "pulse-simple"                       = return "libpulseaudio"
+libNixName "python-3.3"                         = return "python33"
+libNixName "python-3.4"                         = return "python34"
+libNixName "Qt5Core"                            = return "qt5"
+libNixName "Qt5Gui"                             = return "qt5"
+libNixName "Qt5Qml"                             = return "qt5"
+libNixName "Qt5Quick"                           = return "qt5"
+libNixName "Qt5Widgets"                         = return "qt5"
+libNixName "rt"                                 = [] -- in glibc
+libNixName "rtlsdr"                             = return "rtl-sdr"
+libNixName "ruby1.8"                            = return "ruby"
+libNixName "sane-backends"                      = return "saneBackends"
+libNixName "sass"                               = return "libsass"
+libNixName "sdl2"                               = return "SDL2"
+libNixName "SDL2-2.0"                           = return "SDL2"
+libNixName "sndfile"                            = return "libsndfile"
+libNixName "sodium"                             = return "libsodium"
+libNixName "sqlite3"                            = return "sqlite"
+libNixName "ssl"                                = return "openssl"
+libNixName "stdc++"                             = [] -- What is that?
+libNixName "stdc++.dll"                         = [] -- What is that?
+libNixName "systemd-journal"                    = return "systemd"
+libNixName "taglib_c"                           = return "taglib"
+libNixName "tag_c"                              = return "taglib"
+libNixName "udev"                               = return "systemd";
+libNixName "uuid"                               = return "libossp_uuid";
+libNixName "vte-2.90"                           = return "vte"
+libNixName "vte-2.91"                           = return "vte"
+libNixName "wayland-client"                     = return "wayland"
+libNixName "wayland-cursor"                     = return "wayland"
+libNixName "wayland-egl"                        = return "mesa"
+libNixName "wayland-server"                     = return "wayland"
+libNixName "webkit-1.0"                         = return "webkit"
+libNixName "webkit2gtk-4.0"                     = return "webkit2gtk"
+libNixName "webkit2gtk-web-extension-4.0"       = return "webkit2gtk-web-extension"
+libNixName "webkitgtk"                          = return "webkit"
+libNixName "webkitgtk-3.0"                      = return "webkit"
+libNixName "X11"                                = return "libX11"
+libNixName "xau"                                = return "libXau"
+libNixName "Xcursor"                            = return "libXcursor"
+libNixName "xerces-c"                           = return "xercesc"
+libNixName "Xext"                               = return "libXext"
+libNixName "xft"                                = return "libXft"
+libNixName "Xi"                                 = return "libXi"
+libNixName "Xinerama"                           = return "libXinerama"
+libNixName "xkbcommon"                          = return "libxkbcommon"
+libNixName "xml2"                               = return "libxml2"
+libNixName "Xpm"                                = return "libXpm"
+libNixName "Xrandr"                             = return "libXrandr"
+libNixName "Xrender"                            = return "libXrender"
+libNixName "Xss"                                = return "libXScrnSaver"
+libNixName "Xtst"                               = return "libXtst"
+libNixName "Xxf86vm"                            = return "libXxf86vm"
+libNixName "yaml-0.1"                           = return "libyaml"
+libNixName "z"                                  = return "zlib"
+libNixName "zmq"                                = return "zeromq"
+libNixName x                                    = return (fromString x)
+
+-- | Map build tool names to Nix attribute names.
+buildToolNixName :: String -> [Identifier]
+buildToolNixName ""                             = return (error "buildToolNixName: invalid empty dependency name")
+buildToolNixName "cabal"                        = return "cabal-install"
+buildToolNixName "ghc"                          = []
+buildToolNixName "gtk2hsC2hs"                   = return "gtk2hs-buildtools"
+buildToolNixName "gtk2hsHookGenerator"          = return "gtk2hs-buildtools"
+buildToolNixName "gtk2hsTypeGen"                = return "gtk2hs-buildtools"
+buildToolNixName "hsc2hs"                       = []
+buildToolNixName "nix-build"                    = return "nix"
+buildToolNixName "nix-env"                      = return "nix"
+buildToolNixName "nix-instantiate"              = return "nix"
+buildToolNixName "nix-store"                    = return "nix"
+buildToolNixName x                              = return (fromString x)
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs
@@ -0,0 +1,57 @@
+module Distribution.Nixpkgs.Haskell.FromCabal.Normalize ( normalize, normalizeCabalFlags ) where
+
+import Control.Lens
+import Data.Function
+import Data.List
+import qualified Data.Set as Set
+import Data.String
+import Distribution.Nixpkgs.Haskell
+import Distribution.Nixpkgs.Meta
+import Distribution.Package
+import Distribution.PackageDescription ( FlagAssignment, FlagName(..) )
+import Distribution.Simple.Utils ( lowercase )
+import Language.Nix hiding ( quote )
+
+normalize :: Derivation -> Derivation
+normalize drv = drv
+  & over libraryDepends (normalizeBuildInfo (packageName drv))
+  & over executableDepends (normalizeBuildInfo (packageName drv))
+  & over testDepends (normalizeBuildInfo (packageName drv))
+  & over metaSection normalizeMeta
+  & over cabalFlags normalizeCabalFlags
+  & jailbreak %~ (&& (packageName drv /= PackageName "jailbreak-cabal"))
+
+normalizeBuildInfo :: PackageName -> BuildInfo -> BuildInfo
+normalizeBuildInfo (PackageName pname) bi = bi
+  & haskell %~ Set.filter (\b -> view localName b /= fromString pname)
+  & tool %~ Set.filter (\b -> view localName b /= fromString pname)
+
+normalizeMeta :: Meta -> Meta
+normalizeMeta meta = meta
+  & description %~ normalizeSynopsis
+  & platforms %~ Set.intersection allKnownPlatforms
+  & hydraPlatforms %~ Set.intersection (meta^.platforms)
+
+normalizeSynopsis :: String -> String
+normalizeSynopsis desc
+  | null desc                                             = []
+  | last desc == '.' && length (filter ('.'==) desc) == 1 = normalizeSynopsis (init desc)
+  | otherwise                                             = quote (unwords (words desc))
+
+quote :: String -> String
+quote ('\\':c:cs) = '\\' : c : quote cs
+quote ('"':cs)    = '\\' : '"' : quote cs
+quote (c:cs)      = c : quote cs
+quote []          = []
+
+-- |When a flag is specified multiple times, the first occurrence
+-- counts. This is counter-intuitive, IMHO, but it's how cabal does it.
+-- Flag names are spelled in all lowercase.
+--
+-- >>> normalizeCabalFlags [(FlagName "foo", True), (FlagName "FOO", True), (FlagName "Foo", False)]
+-- [(FlagName "foo",True)]
+
+normalizeCabalFlags :: FlagAssignment -> FlagAssignment
+normalizeCabalFlags flags' = nubBy ((==) `on` fst) (sortBy (compare `on` fst) flags)
+  where
+    flags = [ (FlagName (lowercase n), b) | (FlagName n, b) <- flags' ]
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs
@@ -0,0 +1,383 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Distribution.Nixpkgs.Haskell.FromCabal.PostProcess ( postProcess ) where
+
+import Control.Lens
+import Data.List.Split
+import Data.Set ( Set )
+import qualified Data.Set as Set
+import Data.Set.Lens
+import Distribution.Nixpkgs.Haskell
+import Distribution.Nixpkgs.Meta
+import Distribution.Package
+import Distribution.System
+import Distribution.Text
+import Distribution.Version
+import Language.Nix
+
+postProcess :: Derivation -> Derivation
+postProcess deriv = foldr ($) (fixGtkBuilds deriv) [ f | (Dependency n vr, f) <- hooks, packageName deriv == n, packageVersion deriv `withinRange` vr ]
+
+fixGtkBuilds :: Derivation -> Derivation
+fixGtkBuilds drv = drv & dependencies . pkgconfig %~ Set.filter (not . collidesWithHaskellName)
+                       & dependencies . system %~ Set.filter (not . collidesWithHaskellName)
+                       & dependencies . tool %~ Set.filter (not . collidesWithHaskellName)
+  where
+    collidesWithHaskellName :: Binding -> Bool
+    collidesWithHaskellName b = view localName b `Set.member` buildDeps
+
+    myName :: Identifier
+    myName = ident # n where PackageName n = packageName drv
+
+    buildDeps :: Set Identifier
+    buildDeps = Set.delete myName (setOf (dependencies . haskell . folded . localName) drv)
+
+hooks :: [(Dependency, Derivation -> Derivation)]
+hooks =
+  [ ("Agda < 2.5", set (executableDepends . tool . contains (pkg "emacs")) True . set phaseOverrides agdaPostInstall)
+  , ("Agda >= 2.5", set (executableDepends . tool . contains (pkg "emacs")) True . set phaseOverrides agda25PostInstall)
+  , ("alex < 3.1.5",  set (testDepends . tool . contains (pkg "perl")) True)
+  , ("alex",  set (executableDepends . tool . contains (bind "self.happy")) True)
+  , ("bindings-GLFW", over (libraryDepends . system) (Set.union (Set.fromList [bind "pkgs.xorg.libXext", bind "pkgs.xorg.libXfixes"])))
+  , ("bustle", set (libraryDepends . pkgconfig . contains "system-glib = pkgs.glib") True)
+  , ("Cabal", set doCheck False) -- test suite doesn't work in Nix
+  , ("cabal-helper", set doCheck False) -- https://github.com/DanielG/cabal-helper/issues/17
+  , ("cabal-install", set phaseOverrides cabalInstallPostInstall)
+  , ("darcs", set phaseOverrides darcsInstallPostInstall . set doCheck False)
+  , ("dbus", set doCheck False) -- don't execute tests that try to access the network
+  , ("dns", set testTarget "spec")      -- don't execute tests that try to access the network
+  , ("eventstore", over (metaSection . platforms) (Set.filter (\(Platform arch _) -> arch == X86_64)))
+  , ("freenect < 1.2.1", over configureFlags (Set.union (Set.fromList ["--extra-include-dirs=${pkgs.freenect}/include/libfreenect", "--extra-lib-dirs=${pkgs.freenect}/lib"])))
+  , ("gf", set phaseOverrides gfPhaseOverrides . set doCheck False)
+  , ("gi-cairo", giPhaseOverrides)      -- https://github.com/haskell-gi/haskell-gi/issues/36
+  , ("gi-gio", giPhaseOverrides)        -- https://github.com/haskell-gi/haskell-gi/issues/36
+  , ("gi-glib", giPhaseOverrides)       -- https://github.com/haskell-gi/haskell-gi/issues/36
+  , ("gi-gobject", giPhaseOverrides)    -- https://github.com/haskell-gi/haskell-gi/issues/36
+  , ("gi-pango", giPhaseOverrides)      -- https://github.com/haskell-gi/haskell-gi/issues/36
+  , ("gio", set (libraryDepends . pkgconfig . contains "system-glib = pkgs.glib") True)
+  , ("git", set doCheck False)          -- https://github.com/vincenthz/hit/issues/33
+  , ("git-annex", gitAnnexHook)
+  , ("github-backup", set (executableDepends . tool . contains (pkg "git")) True)
+  , ("GlomeVec", set (libraryDepends . pkgconfig . contains (bind "self.llvmPackages.llvm")) True)
+  , ("goatee-gtk", over (metaSection . platforms) (Set.filter (\(Platform _ os) -> os /= OSX)))
+  , ("gtk3", gtk3Hook)
+  , ("haddock", haddockHook) -- https://github.com/haskell/haddock/issues/511
+  , ("hakyll", set (testDepends . tool . contains (pkg "utillinux")) True) -- test suite depends on "rev"
+  , ("haskell-src-exts == 1.17.1", set doCheck False) -- test suite fails with ghc 8.0.1
+  , ("hfsevents", over (metaSection . platforms) (Set.filter (\(Platform _ os) -> os == OSX)))
+  , ("HFuse", set phaseOverrides hfusePreConfigure)
+  , ("hlibgit2 >= 0.18.0.14", set (testDepends . tool . contains (pkg "git")) True)
+  , ("hmatrix", set phaseOverrides "preConfigure = \"sed -i hmatrix.cabal -e 's@/usr/@/dont/hardcode/paths/@'\";")
+  , ("holy-project", set doCheck False)         -- attempts to access the network
+  , ("hsignal < 0.2.7.4", set phaseOverrides "prePatch = \"rm -v Setup.lhs\";") -- https://github.com/amcphail/hsignal/issues/1
+  , ("hslua", over (libraryDepends . each) (replace (pkg "lua") (pkg "lua5_1")))
+  , ("http-client", set doCheck False)          -- attempts to access the network
+  , ("http-client-openssl >= 0.2.0.1", set doCheck False) -- attempts to access the network
+  , ("http-client-tls >= 0.2.2", set doCheck False) -- attempts to access the network
+  , ("http-conduit", set doCheck False)         -- attempts to access the network
+  , ("imagemagick", set (libraryDepends . pkgconfig . contains (pkg "imagemagick")) True) -- https://github.com/NixOS/cabal2nix/issues/136
+  , ("include-file <= 0.1.0.2", set (libraryDepends . haskell . contains (bind "self.random")) True) -- https://github.com/Daniel-Diaz/include-file/issues/1
+  , ("js-jquery", set doCheck False)            -- attempts to access the network
+  , ("jsaddle", set (dependencies . haskell . contains (bind "self.ghcjs-base")) False)
+  , ("libconfig", over (libraryDepends . system) (replace "config = null" (pkg "libconfig")))
+  , ("liquid-fixpoint", set (executableDepends . system . contains (pkg "ocaml")) True . set (testDepends . system . contains (pkg "z3")) True)
+  , ("liquidhaskell", set (testDepends . system . contains (pkg "z3")) True)
+  , ("MFlow < 4.6", set (libraryDepends . tool . contains (bind "self.cpphs")) True)
+  , ("mwc-random", set doCheck False)
+  , ("mysql", set (libraryDepends . system . contains (pkg "mysql")) True)
+  , ("network-attoparsec", set doCheck False) -- test suite requires network access
+  , ("numeric-qq", set doCheck False) -- test suite doesn't finish even after 1+ days
+  , ("pandoc", set jailbreak False) -- jailbreak-cabal break the build
+  , ("pandoc >= 1.16.0.2", set doCheck False) -- https://github.com/jgm/pandoc/issues/2709 and https://github.com/fpco/stackage/issues/1332
+  , ("pandoc-citeproc", set doCheck False) -- https://github.com/jgm/pandoc-citeproc/issues/172
+  , ("readline", over (libraryDepends . system) (Set.union (pkgs ["readline", "ncurses"])))
+  , ("rocksdb-haskell", set (metaSection . platforms) (Set.singleton (Platform X86_64 Linux)))
+  , ("sdr", over (metaSection . platforms) (Set.filter (\(Platform arch _) -> arch == X86_64))) -- https://github.com/adamwalker/sdr/issues/2
+  , ("shake-language-c", set doCheck False) -- https://github.com/samplecount/shake-language-c/issues/26
+  , ("sharc-timbre", set (metaSection . broken) True) -- The build takes insanely long, i.e. >8 hours.
+  , ("ssh", set doCheck False) -- test suite runs forever, probably can't deal with our lack of network access
+  , ("stack", set phaseOverrides stackOverrides . set doCheck False)
+  , ("stripe-http-streams", set doCheck False . set (metaSection . broken) False)
+  , ("target", set (testDepends . system . contains (pkg "z3")) True)
+  , ("terminfo", set (libraryDepends . system . contains (pkg "ncurses")) True)
+  , ("text", set doCheck False)         -- break infinite recursion
+  , ("thyme", set (libraryDepends . tool . contains (bind "self.cpphs")) True) -- required on Darwin
+  , ("twilio", set doCheck False)         -- attempts to access the network
+  , ("tz", set phaseOverrides "preConfigure = \"export TZDIR=${pkgs.tzdata}/share/zoneinfo\";")
+  , ("websockets", set doCheck False)   -- https://github.com/jaspervdj/websockets/issues/104
+  , ("Win32", over (metaSection . platforms) (Set.filter (\(Platform _ os) -> os == Windows)))
+  , ("wxc", wxcHook)
+  , ("wxcore", set (libraryDepends . pkgconfig . contains (pkg "wxGTK")) True)
+  , ("X11", over (libraryDepends . system) (Set.union (Set.fromList $ map bind ["pkgs.xorg.libXinerama","pkgs.xorg.libXext","pkgs.xorg.libXrender"])))
+  , ("xmonad", set phaseOverrides xmonadPostInstall)
+  , ("zip-archive", over (testDepends . tool) (replace (bind "self.zip") (pkg "zip")))
+  ]
+
+pkg :: Identifier -> Binding
+pkg i = binding # (i, path # ["pkgs",i])
+
+pkgs :: [Identifier] -> Set Binding
+pkgs = Set.fromList . map pkg
+
+bind :: String -> Binding
+bind s = binding # (i, path # is)
+  where
+    is = map (review ident) (splitOn "." s)
+    i = last is
+
+replace :: Binding -> Binding -> Set Binding -> Set Binding
+replace old new bs = if old `Set.member` bs then Set.insert new (Set.delete old bs) else bs
+
+-- TODO: I need to figure out how to conveniently replace a binding in a set.
+gtk3Hook :: Derivation -> Derivation    -- https://github.com/NixOS/cabal2nix/issues/145
+gtk3Hook = set (libraryDepends . pkgconfig . contains (pkg "gtk3")) True
+         . over (libraryDepends . pkgconfig) (Set.filter (\b -> view localName b /= "gtk3"))
+
+haddockHook :: Derivation -> Derivation
+haddockHook = set doCheck False
+            . set phaseOverrides "preCheck = \"unset GHC_PACKAGE_PATH\";"
+            . over (dependencies . haskell) (Set.filter (\b -> view localName b /= "haddock-test"))
+            . set (metaSection . broken) False
+
+gitAnnexHook :: Derivation -> Derivation
+gitAnnexHook = set phaseOverrides gitAnnexOverrides
+             . over (executableDepends . system) (Set.union buildInputs)
+             . over (metaSection . platforms) (Set.filter (\(Platform _ os) -> os /= OSX))
+  where
+    gitAnnexOverrides = unlines
+      [ "preConfigure = \"export HOME=$TEMPDIR; patchShebangs .\";"
+      , "postBuild = \"ln -sf dist/build/git-annex/git-annex git-annex\";"
+      , "installPhase = \"make PREFIX=$out CABAL=./Setup BUILDER=./Setup install\";"
+      , "checkPhase = \"./git-annex test\";"
+      , "enableSharedExecutables = false;"
+      ]
+    buildInputs = pkgs ["git","rsync","gnupg","curl","wget","lsof","openssh","which","bup","perl"]
+
+hfusePreConfigure :: String
+hfusePreConfigure = unlines
+  [ "preConfigure = ''"
+  , "  sed -i -e \"s@  Extra-Lib-Dirs:         /usr/local/lib@  Extra-Lib-Dirs:         ${fuse}/lib@\" HFuse.cabal"
+  , "'';"
+  ]
+
+gfPhaseOverrides :: String
+gfPhaseOverrides = unlines
+  [ "postPatch = ''"
+  , "  sed -i \"s|\\\"-s\\\"|\\\"\\\"|\" ./Setup.hs"
+    -- Disable silent compilation. Compiling takes long, it is best to see some
+    -- output, otherwise it looks like the build step has stalled.
+  , "  sed -i \"s|numJobs (bf bi)++||\" ./Setup.hs"
+    -- Parallel compilation fails. Disable it.
+  , "'';"
+  , "preBuild = ''export LD_LIBRARY_PATH=`pwd`/dist/build:$LD_LIBRARY_PATH'';"
+    -- The build step itself, after having built the library, needs to be able
+    -- to find the library it just built in order to compile grammar files.
+  ]
+
+wxcHook :: Derivation -> Derivation
+wxcHook drv = drv & libraryDepends . system %~ Set.union (Set.fromList [pkg "mesa", bind "pkgs.xorg.libX11"])
+                  & libraryDepends . pkgconfig . contains (pkg "wxGTK") .~ True
+                  & phaseOverrides .~ wxcPostInstall (packageVersion drv)
+                  & runHaddock .~ False
+  where
+    wxcPostInstall :: Version -> String
+    wxcPostInstall version = unlines
+      [ "postInstall = \"cp -v dist/build/libwxc.so." ++ display version ++ " $out/lib/libwxc.so\";"
+      , "postPatch = \"sed -i -e '/ldconfig inst_lib_dir/d' Setup.hs\";"
+      ]
+
+cabalInstallPostInstall :: String
+cabalInstallPostInstall = unlines
+  [ "postInstall = ''"
+  , "  mkdir $out/etc"
+  , "  mv bash-completion $out/etc/bash_completion.d"
+  , "'';"
+  ]
+
+darcsInstallPostInstall :: String
+darcsInstallPostInstall = unlines
+  [ "postInstall = ''"
+  , "  mkdir -p $out/etc/bash_completion.d"
+  , "  mv contrib/darcs_completion $out/etc/bash_completion.d/darcs"
+  , "'';"
+  ]
+
+xmonadPostInstall :: String
+xmonadPostInstall = unlines
+  [ "postInstall = ''"
+  , "  shopt -s globstar"
+  , "  mkdir -p $out/share/man/man1"
+  , "  mv \"$out/\"**\"/man/\"*.1 $out/share/man/man1/"
+  , "'';"
+  ]
+
+agdaPostInstall :: String
+agdaPostInstall = unlines
+  [ "postInstall = ''"
+  , "  $out/bin/agda -c --no-main $(find $out/share -name Primitive.agda)"
+  , "  $out/bin/agda-mode compile"
+  , "'';"
+  ]
+
+agda25PostInstall :: String
+agda25PostInstall = unlines
+  [ "postInstall = ''"
+  , "  files=(\"$out/share/\"*\"-ghc-\"*\"/Agda-\"*\"/lib/prim/Agda/\"{Primitive.agda,Builtin\"/\"*.agda})"
+  -- Separate loops to avoid internal error
+  , "  for f in \"''${files[@]}\" ; do"
+  , "    $out/bin/agda $f"
+  , "  done"
+  , "  for f in \"''${files[@]}\" ; do"
+  , "    $out/bin/agda -c --no-main $f"
+  , "  done"
+  , "  $out/bin/agda-mode compile"
+  , "'';"
+  ]
+
+stackOverrides :: String
+stackOverrides = unlines
+  [ "preCheck = \"export HOME=$TMPDIR\";"
+  , "postInstall = ''"
+  , "  exe=$out/bin/stack"
+  , "  mkdir -p $out/share/bash-completion/completions"
+  , "  $exe --bash-completion-script $exe >$out/share/bash-completion/completions/stack"
+  , "'';"
+  ]
+
+giPhaseOverrides :: Derivation -> Derivation
+giPhaseOverrides
+  = set phaseOverrides "preConfigure = \"export HASKELL_GI_GIR_SEARCH_PATH=${gobjectIntrospection.dev}/share/gir-1.0\";"
+  . set (libraryDepends . pkgconfig . contains (pkg "gobjectIntrospection")) True
+
+{-
+postProcess' :: Derivation -> Derivation
+postProcess' deriv@(MkDerivation {..})
+  | pname == "alex" && version < Version [3,1] []
+                                = deriv { buildTools = Set.insert "perl" buildTools }
+  | pname == "alex" && version >= Version [3,1] []
+                                = deriv { buildTools = Set.insert "perl" (Set.insert "happy" buildTools) }
+  | pname == "apache-md5"       = deriv { testDepends = Set.delete "crypto" testDepends }
+  | pname == "bits-extras"      = deriv { configureFlags = Set.insert "--ghc-option=-lgcc_s" configureFlags
+                                        , extraLibs = Set.filter (/= "gcc_s") extraLibs
+                                        }
+  | pname == "Cabal"            = deriv { phaseOverrides = "preCheck = \"unset GHC_PACKAGE_PATH; export HOME=$NIX_BUILD_TOP\";" }
+  | pname == "cabal-bounds"     = deriv { buildTools = Set.insert "cabal-install" buildTools }
+  | pname == "editline"         = deriv { extraLibs = Set.insert "libedit" extraLibs }
+  | pname == "ghc-heap-view"    = deriv { phaseOverrides = ghciPostInstall }
+  | pname == "ghc-mod"          = deriv { phaseOverrides = ghcModPostInstall pname version, buildTools = Set.insert "emacs" buildTools }
+  | pname == "ghc-parser"       = deriv { buildTools = Set.insert "cpphs" (Set.insert "happy" buildTools)
+                                        , phaseOverrides = ghcParserPatchPhase }
+  | pname == "ghc-vis"          = deriv { phaseOverrides = ghciPostInstall }
+  | pname == "github-backup"    = deriv { buildTools = Set.insert "git" buildTools }
+  | pname == "gloss-raster"     = deriv { extraLibs = Set.insert "llvm" extraLibs }
+  | pname == "GLUT"             = deriv { extraLibs = Set.fromList ["glut","libSM","libICE","libXmu","libXi","mesa"] `Set.union` extraLibs }
+  | pname == "gtkglext"         = deriv { pkgConfDeps = Set.insert "pangox_compat" pkgConfDeps }
+  | pname == "gtk2hs-buildtools"= deriv { buildDepends = Set.insert "hashtables" buildDepends }
+  | pname == "happy"            = deriv { buildTools = Set.insert "perl" buildTools }
+  | pname == "haskeline"        = deriv { buildDepends = Set.insert "utf8-string" buildDepends }
+  | pname == "haskell-src"      = deriv { buildTools = Set.insert "happy" buildTools }
+  | pname == "haskell-src-meta" = deriv { buildDepends = Set.insert "uniplate" buildDepends }
+  | pname == "hlibgit2"         = deriv { buildTools = Set.insert "git" buildTools }
+  | pname == "HList"            = deriv { buildTools = Set.insert "diffutils" buildTools }
+  | pname == "hmatrix"          = deriv { extraLibs = Set.insert "liblapack" (Set.insert "blas" (Set.filter (/= "lapack") extraLibs)) }
+  | pname == "hmatrix-special"  = deriv { extraLibs = Set.insert "gsl" extraLibs }
+  | pname == "idris"            = deriv { buildTools = Set.insert "happy" buildTools, extraLibs = Set.insert "gmp" (Set.insert "boehmgc" extraLibs) }
+  | pname == "inline-c-cpp"     = deriv { testDepends = Set.delete "stdc++" testDepends }
+  | pname == "language-c-quote" = deriv { buildTools = Set.insert "alex" (Set.insert "happy" buildTools) }
+  | pname == "language-java"    = deriv { buildDepends = Set.insert "syb" buildDepends }
+  | pname == "lhs2tex"          = deriv { extraLibs = Set.insert "texLive" extraLibs, phaseOverrides = lhs2texPostInstall }
+  | pname == "libffi"           = deriv { extraLibs = Set.delete "ffi" extraLibs }
+  | pname == "liquid-fixpoint"  = deriv { buildTools = Set.insert "z3" (Set.insert "ocaml" buildTools), configureFlags = Set.insert "-fbuild-external" configureFlags }
+  | pname == "liquidhaskell"    = deriv { buildTools = Set.insert "z3" buildTools }
+  | pname == "multiarg"         = deriv { buildDepends = Set.insert "utf8-string" buildDepends }
+  | pname == "ncurses"          = deriv { phaseOverrides = ncursesPatchPhase }
+  | pname == "Omega"            = deriv { testDepends = Set.delete "stdc++" testDepends }
+  | pname == "OpenAL"           = deriv { extraLibs = Set.insert "openal" extraLibs }
+  | pname == "OpenGL"           = deriv { extraLibs = Set.insert "mesa" (Set.insert "libX11" extraLibs) }
+  | pname == "pandoc"           = deriv { buildDepends = Set.insert "alex" (Set.insert "happy" buildDepends) }
+  | pname == "persistent"       = deriv { extraLibs = Set.insert "sqlite3" extraLibs }
+  | pname == "purescript"       = deriv { buildTools = Set.insert "nodejs" buildTools }
+  | pname == "repa-algorithms"  = deriv { extraLibs = Set.insert "llvm" extraLibs }
+  | pname == "repa-examples"    = deriv { extraLibs = Set.insert "llvm" extraLibs }
+  | pname == "SDL-image"        = deriv { extraLibs = Set.insert "SDL_image" extraLibs }
+  | pname == "SDL-mixer"        = deriv { extraLibs = Set.insert "SDL_mixer" extraLibs }
+  | pname == "SDL-ttf"          = deriv { extraLibs = Set.insert "SDL_ttf" extraLibs }
+  | pname == "sloane"           = deriv { phaseOverrides = sloanePostInstall }
+  | pname == "structured-haskell-mode" = deriv { buildTools = Set.insert "emacs" buildTools
+                                               , phaseOverrides = structuredHaskellModePostInstall
+                                               }
+  | pname == "target"           = deriv { buildTools = Set.insert "z3" buildTools }
+  | pname == "threadscope"      = deriv { configureFlags = Set.insert "--ghc-options=-rtsopts" configureFlags }
+  | pname == "vacuum"           = deriv { extraLibs = Set.insert "ghc-paths" extraLibs }
+  | pname == "wxcore"           = deriv { extraLibs = Set.fromList ["wxGTK","mesa","libX11"] `Set.union` extraLibs }
+  | pname == "X11-xft"          = deriv { extraLibs = Set.fromList ["pkgconfig","freetype","fontconfig"] `Set.union` extraLibs
+                                        , configureFlags = Set.insert "--extra-include-dirs=${freetype}/include/freetype2" configureFlags
+                                        }
+-- Unbreak packages during hackage2nix generation:
+
+  | pname == "hnetcdf"          = deriv { testDepends = Set.delete "netcdf" testDepends }
+  | pname == "SDL2-ttf"         = deriv { buildDepends = Set.delete "SDL2" buildDepends }
+  | pname == "hzk"              = deriv { testDepends = Set.delete "zookeeper_mt" testDepends, buildTools = Set.insert "zookeeper_mt" buildTools }
+  | pname == "z3"               = deriv { phaseOverrides = "preBuild = stdenv.lib.optionalString stdenv.isDarwin \"export DYLD_LIBRARY_PATH=${z3}/lib\";" }
+  | otherwise                   = deriv
+
+ghcModPostInstall :: String -> Version -> String
+ghcModPostInstall pname version = unlines
+  [ "configureFlags = \"--datasubdir=" ++ pname ++ "-" ++ display version ++ "\";"
+  , "postInstall = ''"
+  , "  cd $out/share/" ++ pname ++ "-" ++ display version
+  , "  make"
+  , "  rm Makefile"
+  , "  cd .."
+  , "  ensureDir \"$out/share/emacs\""
+  , "  mv " ++ pname ++ "-" ++ display version ++ " emacs/site-lisp"
+  , "'';"
+  ]
+
+ghciPostInstall :: String
+ghciPostInstall = unlines
+  [ "postInstall = ''"
+  , "  ensureDir \"$out/share/ghci\""
+  , "  ln -s \"$out/share/$pname-$version/ghci\" \"$out/share/ghci/$pname\""
+  , "'';"
+  ]
+
+
+lhs2texPostInstall :: String
+lhs2texPostInstall = unlines
+  [ "postInstall = ''"
+  , "  mkdir -p \"$out/share/doc/$name\""
+  , "  cp doc/Guide2.pdf $out/share/doc/$name"
+  , "  mkdir -p \"$out/nix-support\""
+  , "'';"
+  ]
+
+ncursesPatchPhase :: String
+ncursesPatchPhase = "patchPhase = \"find . -type f -exec sed -i -e 's|ncursesw/||' {} \\\\;\";"
+
+
+structuredHaskellModePostInstall :: String
+structuredHaskellModePostInstall = unlines
+  [ "postInstall = ''"
+  , "  emacs -L elisp --batch -f batch-byte-compile \"elisp/\"*.el"
+  , "  install -d $out/share/emacs/site-lisp"
+  , "  install \"elisp/\"*.el \"elisp/\"*.elc  $out/share/emacs/site-lisp"
+  , "'';"
+  ]
+
+sloanePostInstall :: String
+sloanePostInstall = unlines
+  [ "postInstall = ''"
+  , "  mkdir -p $out/share/man/man1"
+  , "  cp sloane.1 $out/share/man/man1/"
+  , "'';"
+  ]
+
+ghcParserPatchPhase :: String
+ghcParserPatchPhase = unlines
+  [ "patchPhase = ''"
+  , "  substituteInPlace build-parser.sh --replace \"/bin/bash\" \"$SHELL\""
+  , "'';"
+  ]
+
+-}
diff --git a/src/Distribution/Nixpkgs/Haskell/Hackage.hs b/src/Distribution/Nixpkgs/Haskell/Hackage.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/Hackage.hs
@@ -0,0 +1,29 @@
+module Distribution.Nixpkgs.Haskell.Hackage ( readHashedHackage, module Distribution.Hackage.DB ) where
+
+import Data.ByteString.Lazy ( ByteString )
+import Data.Digest.Pure.SHA ( sha256, showDigest )
+import Distribution.Hackage.DB
+import qualified Distribution.Hackage.DB.Parsed as Unparsed ( parsePackage )
+import qualified Distribution.Hackage.DB.Unparsed as Unparsed
+
+-- | A variant of 'readHackage' that adds the SHA256 digest of the
+-- original Cabal file to the parsed 'GenericPackageDescription'. That
+-- hash is required to build packages with an "edited" cabal file,
+-- because Nix needs to download the edited file and patch it into the
+-- original tarball.
+
+readHashedHackage :: IO Hackage
+readHashedHackage = fmap parseUnparsedHackage Unparsed.readHackage
+  where
+    parseUnparsedHackage :: Unparsed.Hackage -> Hackage
+    parseUnparsedHackage = mapWithKey (mapWithKey . parsePackage)
+
+    parsePackage :: String -> Version -> ByteString -> GenericPackageDescription
+    parsePackage name version buf =
+      let pkg = Unparsed.parsePackage name version buf
+          hash = showDigest (sha256 buf)
+      in
+       pkg { packageDescription = (packageDescription pkg) {
+                customFieldsPD = ("X-Cabal-File-Hash", hash) : customFieldsPD (packageDescription pkg)
+                }
+           }
diff --git a/src/Distribution/Nixpkgs/Haskell/OrphanInstances.hs b/src/Distribution/Nixpkgs/Haskell/OrphanInstances.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/OrphanInstances.hs
@@ -0,0 +1,116 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DeriveGeneric      #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Distribution.Nixpkgs.Haskell.OrphanInstances ( ) where
+
+import Control.DeepSeq
+import Data.Maybe
+import Data.String
+import qualified Data.Text as T
+import Data.Yaml
+import Distribution.Compiler
+import Distribution.License
+import Distribution.ModuleName hiding ( main, fromString )
+import Distribution.Package
+import Distribution.PackageDescription
+import Distribution.System
+import Distribution.Text
+import Distribution.Version
+import Language.Haskell.Extension
+
+#if !MIN_VERSION_Cabal(1,23,0)
+import GHC.Generics ( Generic )
+deriving instance Generic (CondTree v c a)
+deriving instance Generic (Condition a)
+deriving instance Generic ConfVar
+deriving instance Generic Flag
+deriving instance Generic GenericPackageDescription
+#else
+instance NFData SetupBuildInfo
+#endif
+
+instance (NFData v, NFData c, NFData a) => NFData (CondTree v c a)
+instance NFData Arch
+instance NFData Benchmark
+instance NFData BenchmarkInterface
+instance NFData BenchmarkType
+instance NFData BuildInfo
+instance NFData BuildType
+instance NFData CompilerFlavor
+instance NFData ConfVar
+instance NFData Dependency
+instance NFData Executable
+instance NFData Extension
+instance NFData Flag
+instance NFData FlagName
+instance NFData GenericPackageDescription
+instance NFData KnownExtension
+instance NFData Language
+instance NFData Library
+instance NFData License
+instance NFData ModuleName
+instance NFData ModuleReexport
+instance NFData ModuleRenaming
+instance NFData OS
+instance NFData PackageDescription
+instance NFData RepoKind
+instance NFData RepoType
+instance NFData SourceRepo
+instance NFData TestSuite
+instance NFData TestSuiteInterface
+instance NFData TestType
+instance NFData VersionRange
+instance NFData a => NFData (Condition a)
+instance NFData Platform
+instance NFData CompilerInfo
+instance NFData CompilerId
+instance NFData AbiTag
+
+instance IsString PackageName where
+  fromString = text2isString "PackageName"
+
+instance IsString Version where
+  fromString = text2isString "Version"
+
+instance IsString PackageIdentifier where
+  fromString = text2isString "PackageIdentifier"
+
+instance IsString Dependency where
+  fromString = text2isString "Dependency"
+
+instance IsString CompilerId where
+  fromString = text2isString "CompilerId"
+
+instance IsString Platform where
+  fromString "i686-linux" = Platform I386 Linux
+  fromString "x86_64-linux" = Platform X86_64 Linux
+  fromString "x86_64-darwin" = Platform X86_64 OSX
+  fromString s = error ("fromString: " ++ show s ++ " is not a valid platform")
+
+instance FromJSON Platform where
+  parseJSON (String s) = pure (fromString (T.unpack s))
+  parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid platform")
+
+instance FromJSON PackageName where
+  parseJSON (String s) = return (fromString (T.unpack s))
+  parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Haskell package name")
+
+instance FromJSON PackageIdentifier where
+  parseJSON (String s) = return (fromString (T.unpack s))
+  parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Haskell package identifier")
+
+instance FromJSON Dependency where
+  parseJSON (String s) = return (fromString (T.unpack s))
+  parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Haskell Dependency")
+
+instance FromJSON CompilerInfo where
+  parseJSON (String s) = return (unknownCompilerInfo (fromString (T.unpack s)) NoAbiTag)
+  parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Haskell compiler")
+
+-- parsing tools
+
+text2isString :: Text a => String -> String -> a
+text2isString t s = fromMaybe (error ("fromString: " ++ show s ++ " is not a valid " ++ t)) (simpleParse s)
diff --git a/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs b/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs
@@ -0,0 +1,157 @@
+module Distribution.Nixpkgs.Haskell.PackageSourceSpec
+  ( Package(..), getPackage, sourceFromHackage
+  ) where
+
+import qualified Control.Exception as Exception
+import Control.Monad
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Maybe
+import qualified Data.ByteString.Lazy.Char8 as BS8
+import Data.Digest.Pure.SHA ( sha256, showDigest )
+import Data.List ( isSuffixOf, isPrefixOf )
+import Data.Maybe
+import Data.Version
+import Distribution.Hackage.DB.Parsed
+import Distribution.Nixpkgs.Fetch
+import qualified Distribution.Nixpkgs.Haskell.Hackage as DB
+import qualified Distribution.Package as Cabal
+import Distribution.PackageDescription
+import qualified Distribution.PackageDescription as Cabal
+import Distribution.Text ( simpleParse )
+import System.Directory ( doesDirectoryExist, doesFileExist, createDirectoryIfMissing, getHomeDirectory, getDirectoryContents )
+import System.Exit ( exitFailure )
+import System.FilePath ( (</>), (<.>) )
+import System.IO ( hPutStrLn, stderr, hPutStr )
+
+data Package = Package
+  { pkgSource :: DerivationSource
+  , pkgCabal :: Cabal.GenericPackageDescription
+  }
+  deriving (Show)
+
+getPackage :: Maybe String -> Source -> IO Package
+getPackage optHackageDB source = do
+  (derivSource, pkgDesc) <- fetchOrFromDB optHackageDB source
+  flip Package pkgDesc <$> maybe (sourceFromHackage (sourceHash source) $ showPackageIdentifier pkgDesc) return derivSource
+
+
+fetchOrFromDB :: Maybe String -> Source -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription)
+fetchOrFromDB optHackageDB src
+  | "cabal://" `isPrefixOf` sourceUrl src = fmap ((,) Nothing) . fromDB optHackageDB . drop (length "cabal://") $ sourceUrl src
+  | otherwise                             = do
+    r <- fetch cabalFromPath src
+    case r of
+      Nothing ->
+        hPutStrLn stderr "*** failed to fetch source. Does the URL exist?" >> exitFailure
+      Just (derivSource, (externalSource, pkgDesc)) ->
+        return (derivSource <$ guard externalSource, pkgDesc)
+
+fromDB :: Maybe String -> String -> IO Cabal.GenericPackageDescription
+fromDB optHackageDB pkg = do
+  pkgDesc <- (lookupVersion <=< DB.lookup name) <$> maybe DB.readHashedHackage DB.readHackage' optHackageDB
+  case pkgDesc of
+    Just r -> return r
+    Nothing -> hPutStrLn stderr "*** no such package in the cabal database (did you run cabal update?). " >> exitFailure
+ where
+  pkgId = fromMaybe (error ("invalid Haskell package id " ++ show pkg)) (simpleParse pkg)
+  Cabal.PackageName name = Cabal.pkgName pkgId
+  version = Cabal.pkgVersion pkgId
+
+  lookupVersion :: DB.Map DB.Version Cabal.GenericPackageDescription -> Maybe Cabal.GenericPackageDescription
+  lookupVersion
+    | null (versionBranch version) = fmap snd . listToMaybe . reverse . DB.toAscList
+    | otherwise                    = DB.lookup version
+
+
+readFileMay :: String -> IO (Maybe String)
+readFileMay file = do
+  e <- doesFileExist file
+  if e
+    then Just <$> readFile file
+    else return Nothing
+
+hashCachePath :: String -> IO String
+hashCachePath pid = do
+  home <- getHomeDirectory
+  let cacheDir = home </> ".cache/cabal2nix"
+  createDirectoryIfMissing True cacheDir
+  return $ cacheDir </> pid <.> "sha256"
+
+sourceFromHackage :: Hash -> String -> IO DerivationSource
+sourceFromHackage optHash pkgId = do
+  cacheFile <- hashCachePath pkgId
+  cachedHash <-
+    case optHash of
+      Certain h -> return . Certain $ h
+      Guess   h -> return . Guess $ h
+      _         -> fmap (maybe UnknownHash Certain) . readFileMay $ cacheFile
+  let url = "mirror://hackage/" ++ pkgId ++ ".tar.gz"
+
+  -- Use the cached hash (either from cache file or given on cmdline via sha256 opt)
+  -- if available, otherwise download from hackage to compute hash.
+  case cachedHash of
+    Guess hash -> return $ DerivationSource "url" url "" hash
+    Certain hash ->
+      -- We need to force the hash here. If we didn't do this, then when reading the
+      -- hash from the cache file, the cache file will still be open for reading
+      -- (because lazy io) when writeFile opens the file again for writing. By forcing
+      -- the hash here, we ensure that the file is closed before opening it again.
+      seq (length hash) $
+      DerivationSource "url" url "" hash <$ writeFile cacheFile hash
+    UnknownHash -> do
+      maybeHash <- runMaybeT (derivHash . fst <$> fetchWith (False, "url", []) (Source url "" UnknownHash))
+      case maybeHash of
+        Just hash ->
+          seq (length hash) $
+          DerivationSource "url" url "" hash <$ writeFile cacheFile hash
+        Nothing -> do
+          hPutStr stderr $ unlines
+            [ "*** cannot compute hash. (Not a hackage project?)"
+            , " If your project is not on hackage, please supply the path to the root directory of"
+            , " the project, not to the cabal file."
+            , ""
+            , " If your project is on hackage but you still want to specify the hash manually, you"
+            , " can use the --sha256 option."
+            ]
+          exitFailure
+
+showPackageIdentifier :: Cabal.GenericPackageDescription -> String
+showPackageIdentifier pkgDesc = name ++ "-" ++ showVersion version where
+  pkgId = Cabal.package . Cabal.packageDescription $ pkgDesc
+  Cabal.PackageName name = Cabal.packageName pkgId
+  version = Cabal.packageVersion pkgId
+
+cabalFromPath :: FilePath -> MaybeT IO (Bool, Cabal.GenericPackageDescription)
+cabalFromPath path = do
+  d <- liftIO $ doesDirectoryExist path
+  (,) d <$> if d
+    then cabalFromDirectory  path
+    else cabalFromFile False path
+
+cabalFromDirectory :: FilePath -> MaybeT IO Cabal.GenericPackageDescription
+cabalFromDirectory dir = do
+  cabals <- liftIO $ getDirectoryContents dir >>= filterM doesFileExist . map (dir </>) . filter (".cabal" `isSuffixOf`)
+  case cabals of
+    [cabalFile] -> cabalFromFile True cabalFile
+    _       -> liftIO $ hPutStrLn stderr "*** found zero or more than one cabal file. Exiting." >> exitFailure
+
+handleIO :: (Exception.IOException -> IO a) -> IO a -> IO a
+handleIO = Exception.handle
+
+cabalFromFile :: Bool -> FilePath -> MaybeT IO Cabal.GenericPackageDescription
+cabalFromFile failHard file =
+  -- readFile throws an error if it's used on binary files which contain sequences
+  -- that do not represent valid characters. To catch that exception, we need to
+  -- wrap the whole block in `catchIO`, because of lazy IO. The `case` will force
+  -- the reading of the file, so we will always catch the expression here.
+  MaybeT $ handleIO (\err -> Nothing <$ hPutStrLn stderr ("*** parsing cabal file: " ++ show err)) $ do
+    buf <- BS8.readFile file
+    let hash = showDigest (sha256 buf)
+    case parsePackage' buf of
+      Left msg    -> if failHard
+                     then fail ("*** cannot parse " ++ show file ++ ": " ++ msg)
+                     else return Nothing
+      Right pkg -> do return $ Just $ pkg { packageDescription = (packageDescription pkg) {
+                                               customFieldsPD = ("X-Cabal-File-Hash", hash) : customFieldsPD (packageDescription pkg)
+                                            }
+                                          }
diff --git a/src/cabal2nix.hs b/src/cabal2nix.hs
deleted file mode 100644
--- a/src/cabal2nix.hs
+++ /dev/null
@@ -1,109 +0,0 @@
-module Main ( main ) where
-
-import Cabal2Nix.Generate ( cabal2nix )
-import Cabal2Nix.Normalize ( normalize )
-import Cabal2Nix.Package
-import Cabal2Nix.Version
-import Distribution.NixOS.Derivation.Cabal hiding ( version )
-import Distribution.NixOS.Fetch
-
-import Control.Exception ( bracket )
-import Control.Monad ( when )
-import Distribution.Text ( disp )
-import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )
-import System.Environment ( getArgs )
-import System.Exit ( exitFailure, exitSuccess )
-import System.IO ( hPutStrLn, hFlush, stdout, stderr )
-
-data Configuration = Configuration
-  { optPrintHelp :: Bool
-  , optPrintVersion :: Bool
-  , optSha256 :: Maybe String
-  , optMaintainer :: [String]
-  , optPlatform :: [String]
-  , optHaddock :: Bool
-  , optDoCheck :: Bool
-  , optJailbreak :: Bool
-  , optRevision :: String
-  , optHyperlinkSource :: Bool
-  , optHackageDb :: Maybe FilePath
-  }
-  deriving (Show)
-
-defaultConfiguration :: Configuration
-defaultConfiguration = Configuration
-  { optPrintHelp = False
-  , optPrintVersion = False
-  , optSha256 = Nothing
-  , optMaintainer = []
-  , optPlatform = []
-  , optHaddock = True
-  , optDoCheck = True
-  , optJailbreak = False
-  , optRevision = ""
-  , optHyperlinkSource = True
-  , optHackageDb = Nothing
-  }
-
-options :: [OptDescr (Configuration -> Configuration)]
-options =
-  [ Option "h" ["help"]       (NoArg (\o -> o { optPrintHelp = True }))                                  "show this help text"
-  , Option "v" ["version"]    (NoArg (\o -> o { optPrintVersion = True }))                               "print version"
-  , Option ""  ["hackage-db"] (ReqArg (\x o -> o { optHackageDb = Just x }) "FILEPATH")                  "path to the local hackage db in tar format"
-  , Option ""  ["sha256"]     (ReqArg (\x o -> o { optSha256 = Just x }) "HASH")                         "sha256 hash of source tarball"
-  , Option "m" ["maintainer"] (ReqArg (\x o -> o { optMaintainer = x : optMaintainer o }) "MAINTAINER")  "maintainer of this package (may be specified multiple times)"
-  , Option "p" ["platform"]   (ReqArg (\x o -> o { optPlatform = x : optPlatform o }) "PLATFORM")        "supported build platforms (may be specified multiple times)"
-  , Option ""  ["jailbreak"]  (NoArg (\o -> o { optJailbreak = True }))                                  "don't honor version restrictions on build inputs"
-  , Option ""  ["no-haddock"] (NoArg (\o -> o { optHaddock = False }))                                   "don't run Haddock when building this package"
-  , Option ""  ["no-check"]   (NoArg (\o -> o { optDoCheck = False }))                                   "don't run regression test suites of this package"
-  , Option ""  ["rev"]        (ReqArg (\x o -> o { optRevision = x }) "REVISION")                        "revision, only used when fetching from VCS"
-  , Option ""  ["no-hyperlink-source"] (NoArg (\o -> o { optHyperlinkSource = False }))                  "don't add pretty-printed source code to the documentation"
-  ]
-
-usage :: String
-usage = usageInfo "Usage: cabal2nix [options] URI" options ++ unlines
-        [ ""
-        , "Recognized URI schemes:"
-        , ""
-        , "  cabal://pkgname-pkgversion     download the specified package from Hackage"
-        , "  cabal://pkgname                download latest version of the specified package from Hackage"
-        , "  file:///local/path             load the Cabal file from the local disk"
-        , "  /local/path                    abbreviated version of file URI"
-        , "  <git/svn/bzr/hg URL>           download the source from the specified repository"
-        , ""
-        , "If the URI refers to a cabal file, information for building the package will be retrieved from that file, but "
-        , "hackage will be used as a source for the derivation."
-        , "Otherwise, the supplied URI will be used to as the source for the derivation and the information is taken"
-        , "from the cabal file at the root of the downloaded source."
-        ]
-
-cmdlineError :: String -> IO a
-cmdlineError ""     = hPutStrLn stderr usage >> exitFailure
-cmdlineError errMsg = hPutStrLn stderr errMsg >> cmdlineError ""
-
-main :: IO ()
-main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
-  args' <- getArgs
-  (cfg,args) <- case getOpt Permute options args' of
-                  (o,n,[]  ) -> return (foldl (flip ($)) defaultConfiguration o,n)
-                  (_,_,errs) -> cmdlineError (concatMap ("*** "++) errs)
-
-  when (optPrintHelp cfg) (putStr usage >> exitSuccess)
-  when (optPrintVersion cfg) (putStrLn version >> exitSuccess)
-  when (length args /= 1) (cmdlineError "*** exactly one url-to-cabal-file must be specified\n")
-
-  pkg <- getPackage (optHackageDb cfg) $ Source (head args) (optRevision cfg) (optSha256 cfg)
-
-  let deriv  = (cabal2nix $ cabal pkg) { src = source pkg
-                                       , runHaddock = optHaddock cfg
-                                       , jailbreak = optJailbreak cfg
-                                       , hyperlinkSource = optHyperlinkSource cfg
-                                       }
-      deriv' = deriv { metaSection = (metaSection deriv)
-                                     { maintainers = optMaintainer cfg
-                                     , platforms   = optPlatform cfg
-                                     }
-                     , doCheck = doCheck deriv && optDoCheck cfg
-                     }
-
-  putStr (show (disp (normalize deriv')))
diff --git a/src/hackage4nix.hs b/src/hackage4nix.hs
deleted file mode 100644
--- a/src/hackage4nix.hs
+++ /dev/null
@@ -1,260 +0,0 @@
-module Main ( main ) where
-
-import Cabal2Nix.Generate
-import Cabal2Nix.Normalize
-import Control.Exception ( bracket )
-import Control.Monad.RWS
-import Data.List
-import qualified Data.Set as Set
-import Data.Version
-import qualified Distribution.Hackage.DB as DB
-import Distribution.NixOS.Derivation.Cabal
-import Distribution.Package
-import Distribution.PackageDescription ( GenericPackageDescription() )
-import Distribution.Text
-import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )
-import System.Directory
-import System.Environment
-import System.Exit
-import System.FilePath
-import System.IO
-import Text.Regex.Posix
-
-data Pkg = Pkg Derivation FilePath Bool
-  deriving (Show, Eq, Ord)
-
-type PkgSet = Set.Set Pkg
-
-data Configuration = Configuration
-  { _msgDebug  :: String -> IO ()
-  , _msgInfo   :: String -> IO ()
-  , _hackageDb :: DB.Hackage
-  , _force     :: Bool
-  }
-
-defaultConfiguration :: Configuration
-defaultConfiguration = Configuration
-  { _msgDebug  = hPutStrLn stderr
-  , _msgInfo   = hPutStrLn stderr
-  , _hackageDb = DB.empty
-  , _force     = False
-  }
-
-type Hackage4Nix a = RWST Configuration () PkgSet IO a
-
-io :: (MonadIO m) => IO a -> m a
-io = liftIO
-
-readDirectory :: FilePath -> IO [FilePath]
-readDirectory dirpath = do
-  entries <- getDirectoryContents dirpath
-  return [ x | x <- entries, x /= ".", x /= ".." ]
-
-msgDebug, msgInfo :: String -> Hackage4Nix ()
-msgDebug msg = ask >>= \s -> io (_msgDebug s msg)
-msgInfo msg = ask >>= \s -> io (_msgInfo s msg)
-
-getCabalPackage :: String -> Version -> Hackage4Nix GenericPackageDescription
-getCabalPackage name vers = do
-  db <- asks _hackageDb
-  case DB.lookup name db of
-    Just db' -> case DB.lookup vers db' of
-                  Just pkg -> return pkg
-                  Nothing  -> fail ("hackage doesn't know about " ++ name ++ " version " ++ display vers)
-    Nothing  -> fail ("hackage doesn't know about " ++ show name)
-
-discoverNixFiles :: (FilePath -> Hackage4Nix ()) -> FilePath -> Hackage4Nix ()
-discoverNixFiles yield dirOrFile = do
-  isFile <- io (doesFileExist dirOrFile)
-  case (isFile, takeExtension dirOrFile) of
-    (True,".nix") -> yield dirOrFile
-    (True,_)     -> return ()
-    (False,_)    -> io (readDirectory dirOrFile) >>= mapM_ (discoverNixFiles yield . (dirOrFile </>))
-
-regenerateDerivation :: Derivation -> String -> Bool
-regenerateDerivation _ buf = not (buf =~ "(pre|post)Configure|(pre|post)Install|patchPhase|patches|broken|editedCabalFile")
-
-parseNixFile :: FilePath -> String -> Hackage4Nix (Maybe Pkg)
-parseNixFile path buf
-  | not (buf =~ "cabal.mkDerivation")
-               = msgDebug ("ignore non-cabal package " ++ path) >> return Nothing
-  | any (`isSuffixOf`path) badPackagePaths
-               = msgDebug ("ignore known bad package " ++ path) >> return Nothing
-  | Just deriv <- parseDerivation buf
-               = do forceReGen <- asks _force
-                    let reGen = regenerateDerivation deriv buf
-                    return (Just (Pkg deriv path (forceReGen || reGen)))
-  | otherwise = msgInfo ("failed to parse file " ++ path) >> return Nothing
-
-selectLatestVersions :: PkgSet -> PkgSet
-selectLatestVersions = Set.fromList . nubBy f2 . sortBy f1 . Set.toList
-  where
-    f1 (Pkg deriv1 _ _) (Pkg deriv2 _ _)
-      | pname deriv1 == pname deriv2     = compare (version deriv2) (version deriv1)
-      | otherwise                        = compare (pname deriv1) (pname deriv2)
-    f2 (Pkg deriv1 _ _) (Pkg deriv2 _ _) = pname deriv1 == pname deriv2
-
-discoverUpdates :: String -> Version -> Hackage4Nix [Version]
-discoverUpdates name vers = do
-  db <- asks _hackageDb
-  case DB.lookup name db of
-    Just pkgs -> return (filter (>vers) (DB.keys pkgs))
-    Nothing   -> fail ("discoverUpdates cannot find package " ++ show name ++ " on Hackage")
-
-updateNixPkgs :: [FilePath] -> Hackage4Nix ()
-updateNixPkgs paths = do
-  -- Traverse the given directorcy structure and discover all available
-  -- Haskell packages.
-  forM_ paths $ \fileOrDir -> do
-    msgDebug $ "scanning " ++ show fileOrDir
-    flip discoverNixFiles fileOrDir $ \file -> do
-      nix' <- io (readFile file) >>= parseNixFile file
-      flip (maybe (return ())) nix' $ \nix ->
-        modify (Set.insert nix)
-
-  -- Re-generate all Haskell packages in-place (unless
-  -- 'regenerateDerivation' decided that this particular package
-  -- shouldn't be touched.
-  latestVersions <- gets selectLatestVersions
-  let latestVersionMap :: [(String,Version)]
-      latestVersionMap = [ (pname deriv, version deriv) | Pkg deriv _ _ <- Set.toList latestVersions ]
-  let isLatest :: Derivation -> Bool
-      isLatest deriv = maybe False (version deriv ==) (lookup (pname deriv) latestVersionMap)
-  get >>= \pkgset -> forM_ (Set.toList pkgset) $ \nix -> do
-    let Pkg deriv path regenerate = nix
-        maints = maintainers (metaSection deriv)
-        plats  = platforms (metaSection deriv)
-        hplats = if isLatest deriv then hydraPlatforms (metaSection deriv) else ["self.stdenv.lib.platforms.none"]
-
-    when regenerate $ do
-      msgDebug ("re-generate " ++ path)
-      pkg <- getCabalPackage (pname deriv) (version deriv)
-      let deriv'  = (cabal2nix pkg) { src = src deriv
-                                    , runHaddock = runHaddock deriv
-                                    , doCheck = doCheck deriv
-                                    , jailbreak = jailbreak deriv
-                                    , hyperlinkSource = hyperlinkSource deriv
-                                    , enableSplitObjs = enableSplitObjs deriv
-                                    }
-          meta    = metaSection deriv'
-          plats'  = if null plats then platforms meta else plats
-          deriv'' = deriv' { metaSection = meta
-                                           { maintainers    = maints
-                                           , platforms      = plats'
-                                           , hydraPlatforms = hplats
-                                           }
-                           }
-      io $ writeFile path (show (disp (normalize deriv'')))
-
-  -- Discover available updates and print the appropriate cabal2nix
-  -- command line to the console for the user to execute at his/her
-  -- discretion.
-  updates' <- forM (Set.elems latestVersions) $ \pkg -> do
-    let Pkg deriv _ _ = pkg
-    updates <- discoverUpdates (pname deriv) (version deriv)
-    return (pkg,updates)
-  let updates = [ u | u@(_,_:_) <- updates' ]
-  unless (null updates) $ do
-    msgInfo "The following updates are available:"
-    forM_ updates $ \(pkg,versions) -> do
-      let Pkg deriv path regenerate = pkg
-      msgInfo ""
-      msgInfo $ display (packageId deriv) ++ ":"
-      forM_ versions $ \newVersion -> do
-        let deriv' = deriv { version = newVersion }
-        msgInfo $ "  " ++ genCabal2NixCmdline (Pkg deriv' path regenerate)
-  return ()
-
-genCabal2NixCmdline :: Pkg -> String
-genCabal2NixCmdline (Pkg deriv path _) = unwords $ ["cabal2nix"] ++ opts ++ ['>':path']
-  where
-    meta = metaSection deriv
-    opts = [cabal] ++ maints' ++ plats' ++ hplats'
-                   ++ (if jailbreak deriv then ["--jailbreak"] else [])
-                   ++ (if runHaddock deriv then [] else ["--no-haddock"])
-                   ++ (if doCheck deriv then [] else ["--no-check"])
-    cabal = "cabal://" ++ display (packageId deriv)
-    maints' = [ "--maintainer=" ++ normalizeMaintainer m | m <- maintainers meta ]
-    plats'
-      | ["self.ghc.meta.platforms"] == platforms meta = []
-      | otherwise                                     = [ "--platform=" ++ p | p <- platforms meta ]
-    hplats'
-      | ["self.ghc.meta.platforms"] == platforms meta = []
-      | otherwise                                     = [ "--hydra-platform=" ++ p | p <- hydraPlatforms meta ]
-    path'
-      | path =~ "/[0-9\\.]+\\.nix$" = replaceFileName path (display (version deriv) <.> "nix")
-      | otherwise                   = path
-
-normalizeMaintainer :: String -> String
-normalizeMaintainer x
-  | "self.stdenv.lib.maintainers." `isPrefixOf` x = drop 28 x
-  | otherwise                                     = x
-
-data CliOption = PrintHelp | Verbose | ForceRegen
-  deriving (Eq)
-
-main :: IO ()
-main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
-  let options :: [OptDescr CliOption]
-      options =
-        [ Option "h" ["help"]     (NoArg PrintHelp)                 "show this help text"
-        , Option "v" ["verbose"]  (NoArg Verbose)                   "enable noisy debug output"
-        , Option ""  ["force"]    (NoArg ForceRegen)                "re-generate all files in place"
-        ]
-
-      usage :: String
-      usage = usageInfo "Usage: hackage4nix [options] [dir-or-file ...]" options ++ unlines
-              [ ""
-              , "The purpose of 'hackage4nix' is to keep all Haskell packages in our"
-              , "repository packages up-to-date. It scans a checked-out copy of"
-              , "Nixpkgs for expressions that use 'cabal.mkDerivation', and"
-              , "re-generates them in-place with cabal2nix."
-              ]
-
-      cmdlineError :: String -> IO a
-      cmdlineError ""     = hPutStrLn stderr usage >> exitFailure
-      cmdlineError errMsg = hPutStrLn stderr errMsg >> cmdlineError ""
-
-  args' <- getArgs
-  (opts,args) <- case getOpt Permute options args' of
-     (o,n,[]  ) -> return (o,n)
-     (_,_,errs) -> cmdlineError (concatMap (\e -> '*':'*':'*':' ':e) errs)
-
-  when (PrintHelp `elem` opts) (cmdlineError "")
-
-  hackage <- DB.readHackage
-  let cfg = defaultConfiguration
-            { _msgDebug  = if Verbose `elem` opts then _msgDebug defaultConfiguration else const (return ())
-            , _hackageDb = hackage
-            , _force     = ForceRegen `elem` opts
-            }
-  ((),_,()) <- runRWST (updateNixPkgs args) cfg Set.empty
-  return ()
-
-
--- Packages that cabal2nix cannot generate build expressions for.
-
-badPackagePaths :: [FilePath]
-badPackagePaths = [ -- These expression are not found on Hackage:
-                    "haskell-platform/2009.2.0.2.nix", "haskell-platform/2010.1.0.0.nix"
-                  , "haskell-platform/2010.2.0.0.nix", "haskell-platform/2011.2.0.0.nix"
-                  , "haskell-platform/2011.2.0.1.nix", "haskell-platform/2011.4.0.0.nix"
-                  , "haskell-platform/2012.2.0.0.nix", "haskell-platform/2012.4.0.0.nix"
-                  , "haskell-platform/2013.2.0.0.nix", "compilers/flapjax/default.nix"
-                  , "pkgs/games/uqm/3dovideo.nix",     "haskell/ghcjs-prim/default.nix"
-                  , "system/journal-mailer/default.nix", "development/compilers/ghcjs/default.nix"
-                    -- Our primitive parser cannot handle these files.
-                  , "top-level/all-packages.nix", "top-level/haskell-packages.nix"
-                    -- This build is way too complicated to maintain it automatically.
-                  , "pkgs/development/compilers/pakcs/default.nix"
-                  , "pkgs/development/libraries/haskell/hoogle/local.nix"
-                    -- Not registered on Hackage.
-                  , "pkgs/development/compilers/agda/stdlib.nix"
-                  , "pkgs/development/compilers/cryptol/1.8.x.nix"
-                  , "pkgs/development/compilers/cryptol/2.0.x.nix"
-                  , "pkgs/development/compilers/jhc/default.nix"
-                  , "pkgs/development/tools/haskell/cabal-delete/default.nix"
-                  , "pkgs/tools/networking/sproxy-web/default.nix"
-                  , "pkgs/tools/networking/sproxy/default.nix"
-                  , "pkgs/applications/editors/yi/yi-custom.nix"
-                  ]
diff --git a/test/doc-test.hs b/test/doc-test.hs
deleted file mode 100644
--- a/test/doc-test.hs
+++ /dev/null
@@ -1,37 +0,0 @@
-{-
-   Module      :  Main
-   Copyright   :  (c) 2013 Peter Simons
-   License     :  BSD3
-
-   Maintainer  :  simons@cryp.to
-   Stability   :  provisional
-   Portability :  portable
-
-   Cabal2nix doctest suite.
--}
-
-module Main ( main ) where
-
-import Test.DocTest
-
-main :: IO ()
-main = do
-  let libs = [ "dist/build/autogen/Paths_cabal2nix.hs"
-             , "src/Cabal2Nix/License.hs"
-             , "src/Cabal2Nix/CorePackages.hs"
-             , "src/Cabal2Nix/Flags.hs"
-             , "src/Cabal2Nix/Generate.hs"
-             , "src/Cabal2Nix/Name.hs"
-             , "src/Cabal2Nix/Normalize.hs"
-             , "src/Cabal2Nix/Package.hs"
-             , "src/Cabal2Nix/PostProcess.hs"
-             , "src/Cabal2Nix/Version.hs"
-             , "src/Distribution/NixOS/Derivation/Cabal.hs"
-             , "src/Distribution/NixOS/Derivation/License.hs"
-             , "src/Distribution/NixOS/Derivation/Meta.hs"
-             , "src/Distribution/NixOS/Fetch.hs"
-             , "src/Distribution/NixOS/PrettyPrinting.hs"
-             , "src/Distribution/NixOS/Regex.hs"
-             ]
-  doctest $ "src/cabal2nix.hs" : libs
-  doctest $ "src/hackage4nix.hs" : libs
