diff --git a/cabal2nix.cabal b/cabal2nix.cabal
--- a/cabal2nix.cabal
+++ b/cabal2nix.cabal
@@ -3,7 +3,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           cabal2nix
-version:        2.6
+version:        2.7
 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:
                 .
@@ -101,6 +101,7 @@
     , filepath
     , hackage-db > 2
     , hopenssl >= 2
+    , hpack
     , language-nix
     , lens
     , optparse-applicative
@@ -150,6 +151,7 @@
     , filepath
     , hackage-db > 2
     , hopenssl >= 2
+    , hpack
     , language-nix
     , lens
     , optparse-applicative
@@ -183,6 +185,7 @@
     , filepath
     , hackage-db > 2
     , hopenssl >= 2
+    , hpack
     , language-nix
     , lens
     , optparse-applicative
@@ -223,6 +226,7 @@
     , filepath
     , hackage-db > 2
     , hopenssl >= 2
+    , hpack
     , language-nix
     , lens
     , optparse-applicative
diff --git a/src/Cabal2nix.hs b/src/Cabal2nix.hs
--- a/src/Cabal2nix.hs
+++ b/src/Cabal2nix.hs
@@ -12,11 +12,13 @@
 import Data.Monoid ( (<>) )
 import qualified Data.Set as Set
 import Data.String
+import Data.Time
 import qualified Distribution.Compat.ReadP as P
 import Distribution.Compiler
 import Distribution.Nixpkgs.Fetch
 import Distribution.Nixpkgs.Haskell
 import Distribution.Nixpkgs.Haskell.FromCabal
+import qualified Distribution.Nixpkgs.Haskell.FromCabal.PostProcess as PP (pkg)
 import Distribution.Nixpkgs.Haskell.PackageSourceSpec
 import Distribution.Nixpkgs.Meta
 import Distribution.PackageDescription ( mkFlagName, FlagAssignment )
@@ -36,6 +38,7 @@
   , optMaintainer :: [String]
 --, optPlatform :: [String]       -- TODO: fix command line handling of platforms
   , optHaddock :: Bool
+  , optHpack :: Bool
   , optDoCheck :: Bool
   , optJailbreak :: Bool
   , optRevision :: Maybe String
@@ -50,6 +53,7 @@
   , optCompiler :: CompilerId
   , optSystem :: Platform
   , optSubpath :: Maybe FilePath
+  , optHackageSnapshot :: Maybe UTCTime
   , optUrl :: String
   }
   deriving (Show)
@@ -60,6 +64,7 @@
           <*> 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")
+          <*> switch (long "hpack" <> help "run hpack before configuring this package (only non-hackage packages)")
           <*> 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")
@@ -74,8 +79,17 @@
           <*> 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)
           <*> optional (strOption $ long "subpath" <> metavar "PATH" <> help "Path to Cabal file's directory relative to the URI (default is root directory)")
+          <*> optional (option utcTimeReader (long "hackage-snapshot" <> help "hackage snapshot time, ISO format"))
           <*> strArgument (metavar "URI")
 
+-- | A parser for the date. Hackage updates happen maybe once or twice a month.
+-- Example: parseTime defaultTimeLocale "%FT%T%QZ" "2017-11-20T12:18:35Z" :: Maybe UTCTime
+utcTimeReader :: ReadM UTCTime
+utcTimeReader = eitherReader $ \arg ->
+    case parseTimeM True defaultTimeLocale "%FT%T%QZ" arg of
+        Nothing      -> Left $ "Cannot parse date, ISO format used ('2017-11-20T12:18:35Z'): " ++ arg
+        Just utcTime -> Right utcTime
+
 readP :: P.ReadP a a -> ReadM a
 readP p = eitherReader $ \s -> case [ r' | (r',"") <- P.readP_to_S p s ] of
                                     (r:_) -> Right r
@@ -118,15 +132,21 @@
 main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() ->
   cabal2nix =<< getArgs
 
+hpackOverrides :: Derivation -> Derivation
+hpackOverrides = over phaseOverrides (++ "preConfigure = \"hpack\";")
+               . set (libraryDepends . tool . contains (PP.pkg "hpack")) True
+
 cabal2nix' :: [String] -> IO (Either Doc Derivation)
 cabal2nix' args = do
   Options {..} <- handleParseResult $ execParserPure defaultPrefs pinfo args
 
-  pkg <- getPackage optHackageDb $ Source optUrl (fromMaybe "" optRevision) (maybe UnknownHash Guess optSha256) (fromMaybe "" optSubpath)
+  pkg <- getPackage optHpack optHackageDb optHackageSnapshot $ Source optUrl (fromMaybe "" optRevision) (maybe UnknownHash Guess optSha256) (fromMaybe "" optSubpath)
 
   let
+      withHpackOverrides :: Derivation -> Derivation
+      withHpackOverrides = if pkgRanHpack pkg then hpackOverrides else id
       deriv :: Derivation
-      deriv = fromGenericPackageDescription (const True)
+      deriv = withHpackOverrides $ fromGenericPackageDescription (const True)
                                             (\i -> Just (binding # (i, path # [i])))
                                             optSystem
                                             (unknownCompilerInfo optCompiler NoAbiTag)
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal.hs
--- a/src/Distribution/Nixpkgs/Haskell/FromCabal.hs
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal.hs
@@ -17,7 +17,7 @@
 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 Distribution.Nixpkgs.Haskell.FromCabal.PostProcess (postProcess)
 import qualified Distribution.Nixpkgs.Meta as Nix
 import Distribution.Package
 import Distribution.PackageDescription
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal/Flags.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal/Flags.hs
--- a/src/Distribution/Nixpkgs/Haskell/FromCabal/Flags.hs
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal/Flags.hs
@@ -28,7 +28,7 @@
                                   , enable "s3"
                                   , enable "tahoe"
                                   , enable "tdfa"
-                                  , enable "testsuite"
+                                  , ("testsuite", version `withinRange` "< 6.20170925")
                                   , enable "torrentparser"
                                   , enable "webapp"
                                   , enable "webapp-secure"
@@ -42,7 +42,7 @@
                                 = [enable "externalLibsass"]
  | name == "hmatrix"            = [enable "openblas"]
  | name == "hslua"              = [enable "system-lua"]
- | name == "idris"              = [enable "gmp", enable "ffi", enable "curses"]
+ | name == "idris"              = [enable "gmp", enable "ffi", enable "curses", ("execonly", version `withinRange` (orLaterVersion (mkVersion [1,1,1]))) ]
  | name == "io-streams"         = [enable "NoInteractiveTests"]
  | name == "liquid-fixpoint"    = [enable "build-external"]
  | name == "pandoc"             = [enable "https", disable "trypandoc"]
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs
--- a/src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs
@@ -130,6 +130,7 @@
 libNixName "sass"                               = return "libsass"
 libNixName "sctp"                               = return "lksctp-tools" -- This is linux-specific, we should create a common attribute if we ever add sctp support for other systems.
 libNixName "sdl2"                               = return "SDL2"
+libNixName "ssh2"                               = return "libssh2"
 libNixName "sndfile"                            = return "libsndfile"
 libNixName "sodium"                             = return "libsodium"
 libNixName "sqlite3"                            = return "sqlite"
diff --git a/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs b/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs
--- a/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs
+++ b/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE OverloadedStrings #-}
 
-module Distribution.Nixpkgs.Haskell.FromCabal.PostProcess ( postProcess ) where
+module Distribution.Nixpkgs.Haskell.FromCabal.PostProcess ( postProcess, pkg ) where
 
 import Control.Lens
 import Data.List.Split
@@ -61,6 +61,7 @@
   , ("gi-pangocairo", giCairoPhaseOverrides)                     -- https://github.com/haskell-gi/haskell-gi/issues/36
   , ("gi-pango", giCairoPhaseOverrides)                     -- https://github.com/haskell-gi/haskell-gi/issues/36
   , ("git-annex", gitAnnexHook)
+  , ("git-annex >= 6.20170925", set doCheck False)      -- new version of git-annex require their test suite to be run inside of a git checkout
   , ("github-backup", set (executableDepends . tool . contains (pkg "git")) True)
   , ("git", set doCheck False)          -- https://github.com/vincenthz/hit/issues/33
   , ("gi-webkit", webkitgtk24xHook)   -- https://github.com/haskell-gi/haskell-gi/issues/36
@@ -70,10 +71,11 @@
   , ("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", set doCheck False)
+  , ("hspec-core >= 2.4.4", hspecCoreOverrides)
   , ("hfsevents", hfseventsOverrides)
   , ("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/@'\";")
+  , ("hmatrix", set phaseOverrides "preConfigure = \"sed -i hmatrix.cabal -e '/\\\\/usr\\\\//D'\";")
   , ("holy-project", set doCheck False)         -- attempts to access the network
   , ("hoogle", set testTarget "--test-option=--no-net")
   , ("hsignal < 0.2.7.4", set phaseOverrides "prePatch = \"rm -v Setup.lhs\";") -- https://github.com/amcphail/hsignal/issues/1
@@ -102,6 +104,7 @@
   , ("qtah-cpp-qt5", set (libraryDepends . system . contains (bind "pkgs.qt5.qtbase")) True)
   , ("qtah-qt5", set (libraryDepends . tool . contains (bind "pkgs.qt5.qtbase")) True)
   , ("readline", over (libraryDepends . system) (Set.union (pkgs ["readline", "ncurses"])))
+  , ("req", set doCheck False)  -- test suite requires network access
   , ("sbv > 7", set (testDepends . system . contains (pkg "z3")) True)
   , ("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
@@ -296,3 +299,6 @@
                 . over (libraryDepends . pkgconfig) (replace (pkg "opencv") (pkg "opencv3"))
                 . set (configureFlags . contains "--with-gcc=${stdenv.cc}/bin/c++") True
                 . set (configureFlags . contains "--with-ld=${stdenv.cc}/bin/c++") True
+
+hspecCoreOverrides :: Derivation -> Derivation   -- https://github.com/hspec/hspec/issues/330
+hspecCoreOverrides = set phaseOverrides "testTarget = \"--test-option=--skip --test-option='Test.Hspec.Core.Runner.hspecResult runs specs in parallel'\";"
diff --git a/src/Distribution/Nixpkgs/Haskell/OrphanInstances.hs b/src/Distribution/Nixpkgs/Haskell/OrphanInstances.hs
--- a/src/Distribution/Nixpkgs/Haskell/OrphanInstances.hs
+++ b/src/Distribution/Nixpkgs/Haskell/OrphanInstances.hs
@@ -69,6 +69,9 @@
 instance IsString Version where
   fromString = text2isString "Version"
 
+instance IsString VersionRange where
+  fromString = text2isString "VersionRange"
+
 instance IsString PackageIdentifier where
   fromString = text2isString "PackageIdentifier"
 
diff --git a/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs b/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs
--- a/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs
+++ b/src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs
@@ -9,6 +9,7 @@
 import Data.List ( isSuffixOf, isPrefixOf )
 import qualified Data.Map as DB
 import Data.Maybe
+import Data.Time
 import Distribution.Nixpkgs.Fetch
 import Distribution.Nixpkgs.Hashes
 import qualified Distribution.Nixpkgs.Haskell.Hackage as DB
@@ -18,6 +19,8 @@
 import Distribution.PackageDescription.Parse as Cabal
 import Distribution.Text ( simpleParse, display )
 import Distribution.Version
+import qualified Hpack.Run as Hpack
+import qualified Hpack.Config as Hpack
 import OpenSSL.Digest ( digestString, digestByName )
 import System.Directory ( doesDirectoryExist, doesFileExist, createDirectoryIfMissing, getHomeDirectory, getDirectoryContents )
 import System.Exit ( exitFailure )
@@ -25,30 +28,50 @@
 import System.IO ( hPutStrLn, stderr, hPutStr )
 
 data Package = Package
-  { pkgSource :: DerivationSource
-  , pkgCabal :: Cabal.GenericPackageDescription
+  { pkgSource   :: DerivationSource
+  , pkgRanHpack :: Bool -- ^ If hpack generated a new cabal file
+  , pkgCabal    :: Cabal.GenericPackageDescription
   }
   deriving (Show)
 
-getPackage :: Maybe FilePath -> Source -> IO Package
-getPackage optHackageDB source = do
-  (derivSource, pkgDesc) <- fetchOrFromDB optHackageDB source
-  flip Package pkgDesc <$> maybe (sourceFromHackage (sourceHash source) (showPackageIdentifier pkgDesc) $ sourceCabalDir source) return derivSource
+getPackage :: Bool
+           -- ^ Whether hpack should regenerate the cabal file.
+           -> Maybe FilePath
+           -- ^ The path to the Hackage database.
+           -> Maybe UTCTime
+           -- ^ If we have hackage-snapshot time.
+           -> Source
+           -> IO Package
+getPackage optHpack optHackageDB optHackageSnapshot source = do
+  (derivSource, ranHpack, pkgDesc) <- fetchOrFromDB optHpack optHackageDB optHackageSnapshot source
+  (\s -> Package s ranHpack pkgDesc) <$> maybe (sourceFromHackage (sourceHash source) (showPackageIdentifier pkgDesc) $ sourceCabalDir source) return derivSource
 
-fetchOrFromDB :: Maybe FilePath -> Source -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription)
-fetchOrFromDB optHackageDB src
-  | "cabal://" `isPrefixOf` sourceUrl src = fromDB optHackageDB . drop (length "cabal://") $ sourceUrl src
+fetchOrFromDB :: Bool
+              -- ^ Whether hpack should regenerate the cabal file
+              -> Maybe FilePath
+              -- ^ The path to the Hackage database.
+              -> Maybe UTCTime
+              -- ^ If we have hackage-snapshot time.
+              -> Source
+              -> IO (Maybe DerivationSource, Bool, Cabal.GenericPackageDescription)
+fetchOrFromDB optHpack optHackageDB optHackageSnapshot src
+  | "cabal://" `isPrefixOf` sourceUrl src = do
+      (msrc, pkgDesc) <- fromDB optHackageDB optHackageSnapshot . drop (length "cabal://") $ sourceUrl src
+      return (msrc, False, pkgDesc)
   | otherwise                             = do
-    r <- fetch (\dir -> cabalFromPath (dir </> sourceCabalDir src)) src
+    r <- fetch (\dir -> cabalFromPath optHpack (dir </> sourceCabalDir src)) src
     case r of
       Nothing -> fail "Failed to fetch source. Does the URL exist?"
-      Just (derivSource, (externalSource, pkgDesc)) -> do
-        return (derivSource <$ guard externalSource, pkgDesc)
+      Just (derivSource, (externalSource, ranHpack, pkgDesc)) -> do
+        return (derivSource <$ guard externalSource, ranHpack, pkgDesc)
 
-fromDB :: Maybe FilePath -> String -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription)
-fromDB optHackageDB pkg = do
+fromDB :: Maybe FilePath
+       -> Maybe UTCTime
+       -> String
+       -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription)
+fromDB optHackageDB optHackageSnapshot pkg = do
   dbPath <- maybe DB.hackageTarball return optHackageDB
-  db <- DB.readTarball Nothing dbPath
+  db <- DB.readTarball optHackageSnapshot dbPath
   vd <- maybe unknownPackageError return (DB.lookup name db >>= lookupVersion)
   let ds = case DB.tarballSha256 vd of
              Nothing -> Nothing
@@ -129,22 +152,45 @@
   name = Cabal.unPackageName (Cabal.packageName pkgId)
   version = Cabal.packageVersion pkgId
 
-cabalFromPath :: FilePath -> MaybeT IO (Bool, Cabal.GenericPackageDescription)
-cabalFromPath path = do
+cabalFromPath :: Bool -- ^ Whether hpack should regenerate the cabal file
+              -> FilePath -> MaybeT IO (Bool, Bool, Cabal.GenericPackageDescription)
+cabalFromPath optHpack path = do
   d <- liftIO $ doesDirectoryExist path
-  (,) d <$> if d
-    then cabalFromDirectory  path
-    else cabalFromFile False path
+  if d
+  then do
+    (ranHpack, pkg) <- cabalFromDirectory optHpack path
+    return (d, ranHpack, pkg)
+  else (,,) d False <$> cabalFromFile False path
 
-cabalFromDirectory :: FilePath -> MaybeT IO Cabal.GenericPackageDescription
-cabalFromDirectory dir = do
+cabalFromDirectory :: Bool -- ^ Whether hpack should regenerate the cabal file
+                   -> FilePath -> MaybeT IO (Bool, Cabal.GenericPackageDescription)
+cabalFromDirectory True dir = hpackDirectory dir
+cabalFromDirectory False dir = do
   cabals <- liftIO $ getDirectoryContents dir >>= filterM doesFileExist . map (dir </>) . filter (".cabal" `isSuffixOf`)
   case cabals of
-    [cabalFile] -> cabalFromFile True cabalFile
-    _       -> liftIO $ fail ("Found zero or more than one cabal files: " ++ show cabals ++ ". Exiting.")
+    [] -> do
+      liftIO $ hPutStrLn stderr "*** found zero cabal files. Trying hpack..."
+      hpackDirectory dir
+    [cabalFile] -> (,) False <$> cabalFromFile True cabalFile
+    _       -> liftIO $ fail ("*** found more than one cabal file (" ++ show cabals ++ "). Exiting.")
 
 handleIO :: (Exception.IOException -> IO a) -> IO a -> IO a
 handleIO = Exception.handle
+
+hpackDirectory :: FilePath -> MaybeT IO (Bool, Cabal.GenericPackageDescription)
+hpackDirectory dir = do
+  mPackage <- liftIO $ Hpack.readPackageConfig $ dir </> "package.yaml"
+  case mPackage of
+    Left err -> liftIO $ hPutStrLn stderr ("*** hpack error: " ++ show err ++ ". Exiting.") >> exitFailure
+    Right (_, pkg') -> do
+      let hpackOutput = Hpack.renderPackage Hpack.defaultRenderSettings 2 [] [] pkg'
+          hash = printSHA256 $ digestString (digestByName "sha256") hpackOutput
+      case parseGenericPackageDescription hpackOutput of
+        ParseFailed perr -> liftIO $ do
+          hPutStrLn stderr $ "*** cannot parse hpack output: " ++ show perr
+          hPutStrLn stderr $ "*** hpack output:\n" ++ hpackOutput
+          fail "*** Exiting."
+        ParseOk _ pkg -> MaybeT $ return $ Just $ (,) True $ setCabalFileHash hash pkg
 
 cabalFromFile :: Bool -> FilePath -> MaybeT IO Cabal.GenericPackageDescription
 cabalFromFile failHard file =
