diff --git a/cabal2nix.cabal b/cabal2nix.cabal
--- a/cabal2nix.cabal
+++ b/cabal2nix.cabal
@@ -1,5 +1,5 @@
 Name:                   cabal2nix
-Version:                1.12
+Version:                1.13
 Copyright:              Peter Simons, Andres Loeh
 License:                BSD3
 License-File:           LICENSE
@@ -12,7 +12,7 @@
 Build-Type:             Simple
 Tested-With:            GHC == 6.12.3, GHC == 7.0.4, GHC == 7.2.1
 Description:
-  The cabal2nix utility converts Cabal files into Nix build instructions. The
+  The @cabal2nix@ utility converts Cabal files into Nix build instructions. The
   commandline syntax is:
   .
   > Usage: cabal2nix [options] url-to-cabal-file
@@ -30,8 +30,8 @@
   .
   The only required argument is the path to the cabal file. For example:
   .
-  > cabal2nix http://hackage.haskell.org/packages/archive/cabal2nix/1.9/cabal2nix.cabal
-  > cabal2nix cabal://cabal2nix-1.9
+  > cabal2nix http://hackage.haskell.org/packages/archive/cabal2nix/1.13/cabal2nix.cabal
+  > cabal2nix cabal://cabal2nix-1.13
   .
   If the @--sha256@ option has not been specified, cabal2nix calls
   @nix-prefetch-url@ to determine the hash automatically. This causes
@@ -50,31 +50,25 @@
   Ghc-Options:          -Wall
   other-modules:        Cabal2Nix.CorePackages
                         Cabal2Nix.Flags
+                        Cabal2Nix.Generate
                         Cabal2Nix.Hackage
                         Cabal2Nix.License
                         Cabal2Nix.Name
                         Cabal2Nix.Normalize
-                        Cabal2Nix.Package
                         Cabal2Nix.PostProcess
 
 Executable hackage4nix
   main-is:              Hackage4Nix.hs
   hs-source-dirs:       src
   Build-Depends:        base >= 3 && < 5, regex-posix, pretty, Cabal >= 1.8,
-                        mtl, containers, directory, filepath, nixos-types
+                        mtl, containers, directory, filepath, nixos-types >= 1.1,
+                        hackage-db
   Extensions:           PatternGuards, RecordWildCards, CPP
   Ghc-Options:          -Wall
   other-modules:        Cabal2Nix.CorePackages
                         Cabal2Nix.Flags
+                        Cabal2Nix.Generate
                         Cabal2Nix.License
                         Cabal2Nix.Name
                         Cabal2Nix.Normalize
-                        Cabal2Nix.Package
                         Cabal2Nix.PostProcess
-
-Executable packagelist
-  main-is:              PackageList.hs
-  hs-source-dirs:       src
-  Build-Depends:        base >= 3 && < 5, regex-posix, process, Cabal,
-                        filepath, directory
-  Ghc-Options:          -Wall
diff --git a/src/Cabal2Nix.hs b/src/Cabal2Nix.hs
--- a/src/Cabal2Nix.hs
+++ b/src/Cabal2Nix.hs
@@ -1,7 +1,7 @@
 module Main ( main ) where
 
 import Cabal2Nix.Hackage ( hashPackage, readCabalFile )
-import Cabal2Nix.Package ( cabal2nix )
+import Cabal2Nix.Generate ( cabal2nix )
 import Cabal2Nix.Normalize ( normalize )
 import Distribution.NixOS.Derivation.Cabal
 import Distribution.NixOS.Derivation.Meta
diff --git a/src/Cabal2Nix/Flags.hs b/src/Cabal2Nix/Flags.hs
--- a/src/Cabal2Nix/Flags.hs
+++ b/src/Cabal2Nix/Flags.hs
@@ -1,15 +1,19 @@
-module Cabal2Nix.Flags ( configureFlags ) where
+module Cabal2Nix.Flags ( pkgConfigureFlags ) where
 
 import Distribution.Package
 import Distribution.PackageDescription
 
-configureFlags :: PackageIdentifier -> FlagAssignment
-configureFlags (PackageIdentifier (PackageName name) _)
- | name == "pandoc"     = [enable "highlighting", enable "threaded"]
- | otherwise            = []
+pkgConfigureFlags :: PackageIdentifier -> (FlagAssignment,[String])
+pkgConfigureFlags (PackageIdentifier (PackageName name) _)
+ | name == "pandoc"      = ([enable "highlighting", enable "threaded"],[])
+ | name == "threadscope" = ([], ["--ghc-options=-rtsopts"])
+ | name == "X11-xft"     = ([], ["--extra-include-dirs=${freetype}/include/freetype2"])
+ | otherwise             = ([],[])
 
 enable :: String -> (FlagName,Bool)
 enable name = (FlagName name, True)
 
-disable :: String -> (FlagName,Bool)
-disable name = (FlagName name, False)
+-- Uncommend this function when it's actually used.
+--
+-- disable :: String -> (FlagName,Bool)
+-- disable name = (FlagName name, False)
diff --git a/src/Cabal2Nix/Generate.hs b/src/Cabal2Nix/Generate.hs
new file mode 100644
--- /dev/null
+++ b/src/Cabal2Nix/Generate.hs
@@ -0,0 +1,54 @@
+module Cabal2Nix.Generate ( cabal2nix ) where
+
+import Cabal2Nix.License
+import Cabal2Nix.PostProcess
+import Cabal2Nix.Normalize
+import Cabal2Nix.Flags
+import Data.Maybe
+import Distribution.Compiler
+import qualified Distribution.Package as Cabal
+import qualified Distribution.PackageDescription as Cabal
+import Distribution.PackageDescription.Configuration
+import Distribution.System
+import Distribution.Version
+import Distribution.NixOS.Derivation.Cabal
+
+cabal2nix :: Cabal.GenericPackageDescription -> Derivation
+cabal2nix cabal = normalize $ postProcess $ MkDerivation
+  { pname          = let Cabal.PackageName x = Cabal.pkgName pkg in x
+  , version        = Cabal.pkgVersion pkg
+  , sha256         = "cabal2nix left the she256 field undefined"
+  , isLibrary      = isJust (Cabal.library tpkg)
+  , isExecutable   = not (null (Cabal.executables tpkg))
+  , buildDepends   = map unDep deps
+  , buildTools     = map unDep tools
+  , extraLibs      = libs
+  , pkgConfDeps    = pcs
+  , configureFlags = pkgConfigureFlags pkg
+  , runHaddock     = True
+  , metaSection    = Meta
+                   { homepage    = Cabal.homepage descr
+                   , description = Cabal.synopsis descr
+                   , license     = fromCabalLicense (Cabal.license descr)
+                   , platforms   = []
+                   , maintainers = []
+                   }
+  }
+  where
+    descr   = Cabal.packageDescription cabal
+    pkg     = Cabal.package descr
+    deps    = Cabal.buildDepends tpkg
+    libDeps = map Cabal.libBuildInfo (maybeToList (Cabal.library tpkg))
+    exeDeps = map Cabal.buildInfo (Cabal.executables tpkg)
+    tools   = concatMap Cabal.buildTools (libDeps ++ exeDeps)
+    libs    = concatMap Cabal.extraLibs (libDeps ++ exeDeps)
+    pcs     = map unDep (concatMap Cabal.pkgconfigDepends (libDeps ++ exeDeps))
+    Right (tpkg, _) = finalizePackageDescription
+                        (fst (pkgConfigureFlags pkg))
+                        (const True)
+                        (Platform I386 Linux)                   -- shouldn't be hardcoded
+                        (CompilerId GHC (Version [7,0,4] []))   -- dito
+                        [] cabal
+
+unDep :: Cabal.Dependency -> String
+unDep (Cabal.Dependency (Cabal.PackageName x) _) = x
diff --git a/src/Cabal2Nix/Package.hs b/src/Cabal2Nix/Package.hs
deleted file mode 100644
--- a/src/Cabal2Nix/Package.hs
+++ /dev/null
@@ -1,53 +0,0 @@
-module Cabal2Nix.Package ( cabal2nix ) where
-
-import Cabal2Nix.License
-import Cabal2Nix.PostProcess
-import Cabal2Nix.Normalize
-import Cabal2Nix.Flags
-import Data.Maybe
-import Distribution.Compiler
-import qualified Distribution.Package as Cabal
-import qualified Distribution.PackageDescription as Cabal
-import Distribution.PackageDescription.Configuration
-import Distribution.System
-import Distribution.Version
-import Distribution.NixOS.Derivation.Cabal
-
-cabal2nix :: Cabal.GenericPackageDescription -> Derivation
-cabal2nix cabal = normalize $ postProcess $ MkDerivation
-  { pname        = let Cabal.PackageName x = Cabal.pkgName pkg in x
-  , version      = Cabal.pkgVersion pkg
-  , sha256       = "cabal2nix left the she256 field undefined"
-  , isLibrary    = isJust (Cabal.library tpkg)
-  , isExecutable = not (null (Cabal.executables tpkg))
-  , buildDepends = map unDep deps
-  , buildTools   = map unDep tools
-  , extraLibs    = libs
-  , pkgConfDeps  = pcs
-  , runHaddock   = True
-  , metaSection  = Meta
-                   { homepage    = Cabal.homepage descr
-                   , description = Cabal.synopsis descr
-                   , license     = fromCabalLicense (Cabal.license descr)
-                   , platforms   = []
-                   , maintainers = []
-                   }
-  }
-  where
-    descr = Cabal.packageDescription cabal
-    pkg   = Cabal.package descr
-    deps    = Cabal.buildDepends tpkg
-    libDeps = map Cabal.libBuildInfo (maybeToList (Cabal.library tpkg))
-    exeDeps = map Cabal.buildInfo (Cabal.executables tpkg)
-    tools   = concatMap Cabal.buildTools (libDeps ++ exeDeps)
-    libs    = concatMap Cabal.extraLibs (libDeps ++ exeDeps)
-    pcs     = map unDep (concatMap Cabal.pkgconfigDepends (libDeps ++ exeDeps))
-    Right (tpkg, _) = finalizePackageDescription
-                        (configureFlags pkg)
-                        (const True)
-                        (Platform I386 Linux)                   -- shouldn't be hardcoded
-                        (CompilerId GHC (Version [7,0,4] []))   -- dito
-                        [] cabal
-
-unDep :: Cabal.Dependency -> String
-unDep (Cabal.Dependency (Cabal.PackageName x) _) = x
diff --git a/src/Cabal2Nix/PostProcess.hs b/src/Cabal2Nix/PostProcess.hs
--- a/src/Cabal2Nix/PostProcess.hs
+++ b/src/Cabal2Nix/PostProcess.hs
@@ -30,6 +30,7 @@
   | pname == "terminfo"         = deriv { extraLibs = "ncurses":extraLibs }
   | pname == "vacuum"           = deriv { extraLibs = "ghcPaths":extraLibs }
   | pname == "wxcore"           = deriv { extraLibs = "wxGTK":"mesa":"libX11":extraLibs }
+  | pname == "X11-xft"          = deriv { extraLibs = "pkgconfig":"freetype":"fontconfig":extraLibs }
   | pname == "xmonad"           = deriv { extraLibs = delete "libmpd" extraLibs }
   | pname == "xmonad-extras"    = deriv { buildDepends = delete "libmpd" buildDepends }
   | otherwise                   = deriv
diff --git a/src/Hackage4Nix.hs b/src/Hackage4Nix.hs
--- a/src/Hackage4Nix.hs
+++ b/src/Hackage4Nix.hs
@@ -1,25 +1,26 @@
 module Main ( main ) where
 
-import System.IO
-import System.FilePath
-import System.Directory
-import System.Environment
-import System.Exit
+import Cabal2Nix.Normalize
+import Cabal2Nix.Generate
+import Control.Exception ( bracket )
+import Control.Monad.RWS
 import Data.List
+import Data.Maybe
 import qualified Data.Set as Set
-import Control.Monad.State
-import Control.Exception ( bracket )
-import Text.Regex.Posix
 import Data.Version
-import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )
+import qualified Distribution.Hackage.DB as DB
+import Distribution.NixOS.Derivation.Cabal
+import Distribution.NixOS.Derivation.Meta
 import Distribution.Package
 import Distribution.PackageDescription ( GenericPackageDescription() )
 import Distribution.Text
 import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )
-import Cabal2Nix.Package
-import Cabal2Nix.Normalize
-import Distribution.NixOS.Derivation.Cabal
-import Distribution.NixOS.Derivation.Meta
+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)
@@ -29,19 +30,17 @@
 data Configuration = Configuration
   { _msgDebug  :: String -> IO ()
   , _msgInfo   :: String -> IO ()
-  , _hackageDb :: FilePath
-  , _pkgset    :: PkgSet
+  , _hackageDb :: DB.Hackage
   }
 
 defaultConfiguration :: Configuration
 defaultConfiguration = Configuration
   { _msgDebug  = hPutStrLn stderr
   , _msgInfo   = hPutStrLn stderr
-  , _hackageDb = "/dev/shm/hackage"
-  , _pkgset    = Set.empty
+  , _hackageDb = DB.empty
   }
 
-type Hackage4Nix a = StateT Configuration IO a
+type Hackage4Nix a = RWST Configuration () PkgSet IO a
 
 io :: (MonadIO m) => IO a -> m a
 io = liftIO
@@ -52,18 +51,17 @@
   return [ x | x <- entries, x /= ".", x /= ".." ]
 
 msgDebug, msgInfo :: String -> Hackage4Nix ()
-msgDebug msg = get >>= \s -> io (_msgDebug s msg)
-msgInfo msg = get >>= \s -> io (_msgInfo s msg)
+msgDebug msg = ask >>= \s -> io (_msgDebug s msg)
+msgInfo msg = ask >>= \s -> io (_msgInfo s msg)
 
-readCabalFile :: String -> String -> Hackage4Nix GenericPackageDescription
-readCabalFile name vers = do
-  hackageDir <- gets _hackageDb
-  let cabal = hackageDir </> name </> vers </> name <.> "cabal"
-  pkg' <- fmap parsePackageDescription (io (readFile cabal))
-  pkg <- case pkg' of
-           ParseOk _ a -> return a
-           ParseFailed err -> fail ("cannot parse cabal file " ++ cabal ++ ": " ++ show err)
-  return pkg
+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
@@ -75,10 +73,7 @@
 
 regenerateDerivation :: Derivation -> String -> Bool
 regenerateDerivation deriv buf = not (pname deriv `elem` patchedPackages) &&
-                                 not (buf =~ "(pre|post)Configure|configureFlags|(pre|post)Install|patchPhase")
-
-readVersion :: String -> Version
-readVersion str = maybe (error $ "cannot parse version " ++ show str) id (simpleParse str)
+                                 not (buf =~ "(pre|post)Configure|(pre|post)Install|patchPhase")
 
 parseNixFile :: FilePath -> String -> Hackage4Nix (Maybe Pkg)
 parseNixFile path buf
@@ -100,12 +95,11 @@
       | otherwise                        = compare (pname deriv1) (pname deriv2)
     f2 (Pkg deriv1 _ _) (Pkg deriv2 _ _) = pname deriv1 == pname deriv2
 
-discoverUpdates :: String -> String -> Hackage4Nix [String]
+discoverUpdates :: String -> Version -> Hackage4Nix [Version]
 discoverUpdates name vers = do
-  hackage <- gets _hackageDb
-  versionStrings <- io $ readDirectory (hackage </> name)
-  let versions = map readVersion versionStrings
-  return [ showVersion v | v <- versions, v > readVersion vers ]
+  db <- asks _hackageDb
+  let versions = DB.keys (fromJust (DB.lookup name db))
+  return (filter (>vers) versions)
 
 updateNixPkgs :: [FilePath] -> Hackage4Nix ()
 updateNixPkgs paths = do
@@ -117,10 +111,10 @@
         let Pkg deriv path regenerate = nix
             maints = maintainers (metaSection deriv)
             plats  = platforms (metaSection deriv)
-        modify $ \cfg -> cfg { _pkgset = Set.insert nix (_pkgset cfg) }
+        modify (Set.insert nix)
         when regenerate $ do
           msgDebug ("re-generate " ++ path)
-          pkg <- readCabalFile (pname deriv) (display (version deriv))
+          pkg <- getCabalPackage (pname deriv) (version deriv)
           let deriv'  = (cabal2nix pkg) { sha256 = sha256 deriv, runHaddock = runHaddock deriv }
               meta    = metaSection deriv'
               plats'  = if null plats then platforms meta else plats
@@ -130,10 +124,10 @@
                                                }
                                }
           io $ writeFile path (show (disp (normalize (deriv''))))
-  pkgset <- gets (selectLatestVersions . _pkgset)
+  pkgset <- gets selectLatestVersions
   updates' <- flip mapM (Set.elems pkgset) $ \pkg -> do
     let Pkg deriv _ _ = pkg
-    updates <- discoverUpdates (pname deriv) (display (version deriv))
+    updates <- discoverUpdates (pname deriv) (version deriv)
     return (pkg,updates)
   let updates = [ u | u@(_,(_:_)) <- updates' ]
   when (not (null updates)) $ do
@@ -143,7 +137,7 @@
       msgInfo ""
       msgInfo $ (display (packageId deriv)) ++ ":"
       flip mapM_ versions $ \newVersion -> do
-        let deriv' = deriv { version = readVersion newVersion }
+        let deriv' = deriv { version = newVersion }
         msgInfo $ "  " ++ genCabal2NixCmdline (Pkg deriv' path regenerate)
   return ()
 
@@ -185,15 +179,6 @@
               , "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."
-              , ""
-              , "Because we don't want to generate a barrage of HTTP requests during"
-              , "that procedure, the tool expects a copy of the Hackage database"
-              , "available at some local path, i.e. \"/dev/shm/hackage\" by default."
-              , "That directory can be set up as follows:"
-              , ""
-              , "  cabal update"
-              , "  mkdir -p /dev/shm/hackage"
-              , "  tar xf ~/.cabal/packages/hackage.haskell.org/00-index.tar -C /dev/shm/hackage\n"
               ]
 
       cmdlineError :: String -> IO a
@@ -207,11 +192,13 @@
 
   when (PrintHelp `elem` opts) (cmdlineError "")
 
+  hackage <- DB.readHackage
   let cfg = defaultConfiguration
             { _msgDebug  = if Verbose `elem` opts then _msgDebug defaultConfiguration else const (return ())
-            , _hackageDb = last $ _hackageDb defaultConfiguration : [ p | HackageDB p <- opts ]
+            , _hackageDb = hackage
             }
-  flip evalStateT cfg (updateNixPkgs args)
+  ((),_,()) <- runRWST (updateNixPkgs args) cfg Set.empty
+  return ()
 
 
 -- Packages that we cannot parse.
diff --git a/src/PackageList.hs b/src/PackageList.hs
deleted file mode 100644
--- a/src/PackageList.hs
+++ /dev/null
@@ -1,73 +0,0 @@
-module Main ( main ) where
-
-import Control.Exception ( assert )
-import Control.Monad ( when, filterM )
-import Data.Char ( toLower )
-import Data.List ( nubBy, sortBy )
-import Data.Ord ( comparing )
-import Data.Version ( Version(..) )
-import Distribution.Package ( PackageIdentifier(..), PackageName(..) )
-import Distribution.Text ( simpleParse, display )
-import System.Directory ( doesDirectoryExist, doesFileExist )
-import System.FilePath ( (</>), (<.>) )
-import System.Process ( readProcess )
-import Text.Regex.Posix ( (=~), match, makeRegexOpts, compExtended, execBlank )
-
-type Pkg    = (String,Version,String) -- (Name, Version, Attribute)
-type Pkgset = [Pkg]
-
-comparePkgByVersion :: Pkg -> Pkg -> Ordering  -- prefers the latest version
-comparePkgByVersion (n1,v1,a1) (n2,v2,a2)
-  | a1 == a2    = assert (n1 == n2) (compare v2 v1)
-  | otherwise   = compare a2 a1
-
-comparePkgByName :: Pkg -> Pkg-> Ordering
-comparePkgByName (n1,_,_) (n2,_,_) = comparing (map toLower) n1 n2
-
-parseHaskellPackageName :: String -> Maybe Pkg
-parseHaskellPackageName name =
-  case name `regsubmatch` "^(haskellPackages[^ \t]+)[ \t]+(.+)$" of
-    [attr,name'] -> case name' `regsubmatch` "^haskell-(.+)-ghc[0-9.]+-(.+)$" of
-                      [name'',version] -> case simpleParse version of
-                                            Just version' -> Just (name'',version',attr)
-                                            _             -> error ("cannot parse " ++ show name)
-                      _                -> case simpleParse name' of
-                                            Just (PackageIdentifier (PackageName n) v) -> Just (n,v,attr)
-                                            _                                          -> error ("cannot parse " ++ show name)
-    _            -> Nothing
-
-getHaskellPackageList :: IO Pkgset
-getHaskellPackageList = do
-  allPkgs <- fmap lines (readProcess "bash" ["-c", "exec nix-env -qaP \\* 2>/dev/tty"] "")
-  return [ p | Just p <- map parseHaskellPackageName allPkgs ]
-
-stripProfilingVersions :: Pkgset -> Pkgset
-stripProfilingVersions pkgs = [ p | p@(_,_,attr) <- pkgs , not (attr =~ "ghc[0-9.]+_profiling") ]
-
-stripGhc721Versions :: Pkgset -> Pkgset
-stripGhc721Versions pkgs = [ p | p@(_,_,attr) <- pkgs , not (attr =~ "ghc721") ]
-
-selectLatestVersions :: Pkgset -> Pkgset
-selectLatestVersions = nubBy (\x y -> comparePkgByName x y == EQ) . sortBy comparePkgByVersion
-
-isHackagePackage :: Pkg -> IO Bool
-isHackagePackage (name,version,_) = doesFileExist path
-  where path = "/dev/shm/hackage/" </> name </> display version </> name <.> "cabal"
-
-formatPackageLine :: Pkg -> String
-formatPackageLine (name,version,attr) = show (name, display version, Just url)
-  where
-    url = "http://hydra.nixos.org/job/nixpkgs/trunk/" ++ attr
-
-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
-
-main :: IO ()
-main = do
-  haveHackage <- doesDirectoryExist "/dev/shm/hackage"
-  when (not haveHackage) (fail "cannot find hackage database at /dev/shm/hackage")
-  pkgset' <- fmap (selectLatestVersions . stripGhc721Versions . stripProfilingVersions) getHaskellPackageList
-  pkgset <- filterM isHackagePackage pkgset'
-  mapM_ (putStrLn . formatPackageLine) (sortBy comparePkgByName pkgset)
