packages feed

cabal2nix 1.7 → 1.8

raw patch · 4 files changed

+416/−174 lines, 4 filesdep +bytestringdep +containersdep +directorynew-component:exe:hackage4nix

Dependencies added: bytestring, containers, directory, filepath, mtl, pretty, regex-posix

Files

cabal2nix.cabal view
@@ -1,40 +1,55 @@ Name:                   cabal2nix-Version:                1.7-Copyright:              (c) 2011 Peter Simons+Version:                1.8+Copyright:              (c) 2011 Peter Simons and Andres Loeh License:                BSD3 License-File:           LICENSE-Author:                 Peter Simons <simons@cryp.to>-Maintainer:             Peter Simons <simons@cryp.to>-Homepage:               http://github.com/peti/cabal2nix+Author:                 Peter Simons <simons@cryp.to>, Andres Loeh <mail@andres-loeh.de>+Maintainer:             Nix Developers <nix-dev@cs.uu.nl>+Homepage:               http://github.com/haskell4nix/cabal2nix Category:               Distribution Synopsis:               Convert Cabal files into Nix build instructions Cabal-Version:          >= 1.6 Build-Type:             Simple Tested-With:            GHC == 7.0.4-Description:            This utility converts Cabal files into Nix build-			instructions. The commandline syntax is:-			.-			> cabal2nix cabal-file-uri [sha256-hash]-			.-			The first argument is the path to the cabal-			file. That path can be an HTTP URL or local file-			path. For example:-			.-			> cabal2nix http://hackage.haskell.org/packages/archive/cabal2nix/1.7/cabal2nix.cabal-			> cabal2nix file:///tmp/cabal2nix.cabal-			> cabal2nix /tmp/cabal2nix.cabal 0m7zgsd1pxmw504xpvl7dg25ana6dkk1mcyjj4c1wdbkvhvbn3gn-			.-			The second argument -- the hash of the source-			tarball -- is optional. If it's not specified,-			cabal2nix calls @nix-prefetch-url@ to determine-			the hash automatically. This causes network-			traffic, obviously.+Description:+  The cabal2nix utility converts Cabal files into Nix build instructions. The+  commandline syntax is:+  .+  > Usage: cabal2nix [options] url-to-cabal-file+  >   -h             --help                   show this help text+  >                  --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)+  >+  > Recognized URI schemes:+  >+  >   cabal://pkgname-pkgversion       download the specified package from Hackage+  >   http://host/path                 fetch the Cabel file via HTTP+  >   file:///local/path               load the Cabal file from the local disk+  >   /local/path                      abbreviated version of file URI+  .+  The only required argument is the path to the cabal file. For example:+  .+  > cabal2nix http://hackage.haskell.org/packages/archive/cabal2nix/1.8/cabal2nix.cabal+  > cabal2nix cabal://cabal2nix-1.8+  .+  If the @--sha256@ option has not been specified, cabal2nix calls+  @nix-prefetch-url@ to determine the hash automatically. This causes+  network traffic, obviously.  Source-Repository head   Type:                 git-  Location:             git://github.com/peti/cabal2nix.git+  Location:             git://github.com/haskell4nix/cabal2nix.git  Executable cabal2nix-  main-is:              cabal2nix.hs-  Build-Depends:        base >= 3 && < 5, Cabal, process, HTTP+  main-is:              Cabal2Nix.hs+  hs-source-dirs:       src+  Build-Depends:        base >= 3 && < 5, Cabal, process, HTTP, pretty, filepath, directory+  Ghc-Options:          -Wall++Executable hackage4nix+  main-is:              Hackage4Nix.hs+  hs-source-dirs:       src+  Build-Depends:        base >= 3 && < 5, Cabal, pretty, filepath, directory, bytestring,+                        regex-posix, mtl, containers   Ghc-Options:          -Wall
− cabal2nix.hs
@@ -1,148 +0,0 @@--- cabal2nix.hs------ Copyright (c) 20011 Peter Simons <simons@cryp.to>--- See LICENSE file for licensing details.--module Main ( main ) where--import System.IO-import System.Environment-import Control.Exception-import System.Exit-import Distribution.PackageDescription.Parse-import Distribution.PackageDescription-import Distribution.Package-import Distribution.License-import Data.Version-import Data.List-import Control.Monad-import Data.Char-import Network.HTTP-import System.Process--type PkgName = String-type PkgVersion = [Int]-type PkgSHA256 = String-type PkgURL = String-type PkgDescription = String-type PkgLicense = License-type PkgDependencies = [CondTree ConfVar [Dependency] ()]-type PkgExtraLibs = [String]--data Pkg = Pkg PkgName PkgVersion PkgSHA256 PkgURL PkgDescription PkgLicense PkgDependencies PkgExtraLibs-  deriving (Show)--toNixName :: String -> String-toNixName [] = error "toNixName: empty string is not a valid argument"-toNixName "Cabal" = "cabal"-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--toNix :: Pkg -> String-toNix (Pkg name ver sha256 url desc lic deps libs) =-       "{" ++ exprArgs ++"}:\n\n"-    ++ "cabal.mkDerivation (self : {\n"-    ++ "  pname = " ++ show name ++ ";\n"-    ++ "  version = \"" ++ showVer ++ "\";\n"-    ++ "  sha256 = " ++ show sha256 ++ ";\n"-    ++ "  propagatedBuildInputs = [" ++ depList ++ "];\n"-    ++ "  meta = {\n"-    ++ "    homepage = \"" ++ url ++ "\";\n"-    ++ "    description = " ++ show desc ++ ";\n"-    ++ "    license = " ++ showLic lic ++ ";\n"-    ++ "  };\n"-    ++ "})\n"-    where-      exprArgs = concat (intersperse "," ("cabal":pkgDeps))-      showVer = concat (intersperse "." (map show ver))-      depList = concat (intersperse " " pkgDeps)-      pkgDeps :: [String]-      pkgDeps = filter (/="cabal") $ nub $ sort $ map toNixName $-                  libs ++ [ n | dep <- deps, Dependency (PackageName n) _ <- condTreeConstraints dep-                              , n `notElem` ["base","containers"]-                          ]-      showLic (GPL Nothing)                     = show "GPL"-      showLic (GPL (Just (Version [2] [])))     = "self.stdenv.lib.licenses.gpl2"-      showLic (GPL (Just (Version [3] [])))     = "self.stdenv.lib.licenses.gpl3"-      showLic (LGPL Nothing)                    = show "LGPL"-      showLic (LGPL (Just (Version [2,1] [])))  = "self.stdenv.lib.licenses.lgpl21"-      showLic (LGPL (Just (Version [3] [])))    = "self.stdenv.lib.licenses.lgpl3"-      showLic BSD3                              = "self.stdenv.lib.licenses.bsd3"-      showLic BSD4                              = "self.stdenv.lib.licenses.bsd4"-      showLic MIT                               = "self.stdenv.lib.licenses.mit"-      showLic PublicDomain                      = "self.stdenv.lib.licenses.publicDomain"-      showLic AllRightsReserved                 = "unknown"-      showLic OtherLicense                      = "unknown"-      showLic l                                 = error $ "unknown license: " ++ show l--cabal2nix :: GenericPackageDescription -> PkgSHA256 -> Pkg-cabal2nix cabal sha256 = Pkg pkgname pkgver sha256 url desc lic (map simplify libDeps ++ map simplify exeDeps) (libs++libs')-  where-    pkg = packageDescription cabal-    PackageName pkgname = pkgName (package pkg)-    pkgver = versionBranch (pkgVersion (package pkg))-    lic = license pkg-    url = homepage pkg-    desc = synopsis pkg-    -- globalDeps = buildDepends pkg-    libDeps = maybe [] (\x -> [x]) (condLibrary cabal)-    exeDeps = [ tree | (_,tree) <- condExecutables cabal ]-    libs = concat [ extraLibs (libBuildInfo (condTreeData x)) | x <- libDeps ]-    libs' = concat [ extraLibs (buildInfo (condTreeData x)) | x <- exeDeps ]--simplify :: CondTree ConfVar [Dependency] a -> CondTree ConfVar [Dependency] ()-simplify (CondNode _ deps nodes) = CondNode () deps (map simp nodes)-  where-    simp (cond,tree,mtree) = (cond, simplify tree, maybe Nothing (Just . simplify) mtree)--readCabalFile :: FilePath -> IO String-readCabalFile path-  | "http://" `isPrefixOf` path = Network.HTTP.simpleHTTP (getRequest path) >>= getResponseBody-  | "file://" `isPrefixOf` path = readCabalFile (drop 7 path)-  | otherwise                   = readFile path--hashPackage :: GenericPackageDescription -> IO String-hashPackage pkg = do-    hash <- readProcess "bash" ["-c", "exec nix-prefetch-url 2>/dev/tty " ++ url] ""-    return (reverse (dropWhile (=='\n') (reverse hash)))--  where-    url = "http://hackage.haskell.org/packages/archive/" ++ name ++ "/" ++ version ++ "/" ++ name ++ "-" ++ version ++ ".tar.gz"-    PackageIdentifier (PackageName name) version' = package (packageDescription pkg)-    version = showVersion version'--main :: IO ()-main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do-  args <- getArgs--  let usage = "Usage: cabal2nix url-to-cabal-file [sha256-hash]"--  when (length args < 1 || length args > 2) $ do-    mapM_ (hPutStrLn stderr) [ "*** invalid command line syntax"-                             , usage-                             ]-    exitFailure--  when ("--help" `elem` args || "-h" `elem` args) $ do-    putStrLn usage-    exitFailure--  cabal' <- fmap parsePackageDescription (readCabalFile (head args))-  cabal <- case cabal' of-             ParseOk _ a -> return a-             ParseFailed err -> do-               hPutStrLn stderr ("*** cannot parse cabal file: " ++ show err)-               exitFailure--  sha256 <- case args of-              _:hash:[] -> return hash-              _         -> hashPackage cabal--  let pkg = cabal2nix cabal sha256-  putStr (toNix pkg)--
+ src/Cabal2Nix.hs view
@@ -0,0 +1,81 @@+module Main ( main ) where++import System.IO ( hPutStrLn, hFlush, stdout, stderr )+import System.Environment ( getArgs )+import Control.Exception ( bracket )+import System.Exit ( exitFailure )+import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )+import Distribution.PackageDescription ( package, packageDescription )+import Distribution.Text ( simpleParse )+import Data.List ( isPrefixOf )+import Control.Monad ( when )+import Network.HTTP ( simpleHTTP, getRequest, getResponseBody )+import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )++import Cabal2Nix.Package ( showNixPkg, cabal2nix )+import Cabal2Nix.Hackage ( hackagePath, Ext(..), hashPackage )++readCabalFile :: FilePath -> IO String+readCabalFile path+  | "cabal://" `isPrefixOf` path = let Just pid = simpleParse (drop 8 path) in readCabalFile (hackagePath pid Cabal)+  | "http://"  `isPrefixOf` path = simpleHTTP (getRequest path) >>= getResponseBody+  | "file://"  `isPrefixOf` path = readCabalFile (drop 7 path)+  | otherwise                    = readFile path++data CliOption = PrintHelp | SHA256 String | Maintainer String | Platform String+  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 []    ["sha256"]     (ReqArg SHA256 "HASH")            "sha256 hash of source tarball"+        , Option ['m'] ["maintainer"] (ReqArg Maintainer "MAINTAINER")  "maintainer of this package (may be specified multiple times)"+        , Option ['p'] ["platform"]   (ReqArg Platform "PLATFORM")      "supported build platforms (may be specified multiple times)"+        ]++      usage :: String+      usage = usageInfo "Usage: cabal2nix [options] url-to-cabal-file" options +++             "\n\+             \Recognized URI schemes:\n\+             \\n\+             \  cabal://pkgname-pkgversion       download the specified package from Hackage\n\+             \  http://host/path                 fetch the Cabel file via HTTP\n\+             \  file:///local/path               load the Cabal file from the local disk\n\+             \  /local/path                      abbreviated version of file URI\n"++      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 "")++  let uri         = args+      hash        = [ h | SHA256 h <- opts ]+      maintainers = [ m | Maintainer m <- opts ]+      platforms'  = [ p | Platform p <- opts ]+      platforms+        | null platforms' = if not (null maintainers) then ["self.ghc.meta.platforms"] else []+        | otherwise       = platforms'++  when (length uri /= 1) (cmdlineError "*** exactly one URI must be specified")+  when (length hash > 1) (cmdlineError "*** the --sha256 option may be specified only once")++  cabal' <- fmap parsePackageDescription (readCabalFile (head uri))+  cabal <- case cabal' of+             ParseOk _ a -> return a+             ParseFailed err -> do+               hPutStrLn stderr ("*** cannot parse cabal file: " ++ show err)+               exitFailure++  let packageId = package (packageDescription cabal)++  sha256 <- if null hash then hashPackage packageId else return (head hash)++  putStr (showNixPkg (cabal2nix cabal sha256 platforms maintainers))
+ src/Hackage4Nix.hs view
@@ -0,0 +1,294 @@+{-# LANGUAGE OverloadedStrings, PatternGuards #-}++module Main ( main ) where++import System.IO+import System.FilePath+import System.Directory+import System.Environment+import System.Exit+import Data.List+import qualified Data.Set as Set+import Control.Monad.State+import Control.Exception ( bracket )+import qualified Data.ByteString.Char8 as BS+import Text.Regex.Posix+import Data.Version+import Text.ParserCombinators.ReadP ( readP_to_S )+import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )+import Distribution.PackageDescription ( GenericPackageDescription() )+import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )+import Cabal2Nix.Package ( cabal2nix, showNixPkg, PkgName, PkgSHA256, PkgPlatforms, PkgMaintainers )++type ByteString = BS.ByteString++pack :: String -> ByteString+pack = BS.pack++unpack :: ByteString -> String+unpack = BS.unpack++type PkgSet = Set.Set Pkg++data Configuration = Configuration+  { _msgDebug  :: String -> IO ()+  , _msgInfo   :: String -> IO ()+  , _hackageDb :: FilePath+  , _pkgset    :: PkgSet+  }++defaultConfiguration :: Configuration+defaultConfiguration = Configuration+  { _msgDebug  = hPutStrLn stderr+  , _msgInfo   = hPutStrLn stderr+  , _hackageDb = "/dev/shm/hackage"+  , _pkgset    = Set.empty+  }++type Hackage4Nix a = StateT Configuration 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 = get >>= \s -> io (_msgDebug s msg)+msgInfo msg = get >>= \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++discoverNixFiles :: (FilePath -> Hackage4Nix ()) -> FilePath -> Hackage4Nix ()+discoverNixFiles yield dirOrFile+  | "." `isPrefixOf` takeFileName dirOrFile  = msgDebug $ "ignore file or directory " ++ dirOrFile+  | otherwise                                = do+     isFile <- io (doesFileExist dirOrFile)+     case (isFile, takeExtension dirOrFile) of+       (True,".nix") -> do+         msgDebug ("discovered file " ++ dirOrFile)+         yield dirOrFile+       (True,_) -> msgDebug $ "ignore file " ++ dirOrFile+       (False,_) -> do+         msgDebug ("discovered dir " ++ dirOrFile)+         io (readDirectory dirOrFile) >>= mapM_ (discoverNixFiles yield . (dirOrFile </>))++type PkgVersion = String+data Pkg = Pkg PkgName PkgVersion PkgSHA256 PkgPlatforms PkgMaintainers FilePath+  deriving (Show, Eq, Ord)++regmatch :: ByteString -> String -> Bool+regmatch buf patt = match (makeRegexOpts compExtended execBlank (pack patt)) buf++regsubmatch :: ByteString -> String -> [ByteString]+regsubmatch buf patt = let (_,_,_,x) = f in x+  where f :: (ByteString,ByteString,ByteString,[ByteString])+        f = match (makeRegexOpts compExtended execBlank (pack patt)) buf++normalizeMaintainer :: String -> String+normalizeMaintainer x+  | "self.stdenv.lib.maintainers." `isPrefixOf` x = drop 28 x+  | otherwise                                     = x++parseNixFile :: FilePath -> ByteString -> Hackage4Nix (Maybe Pkg)+parseNixFile path buf+  | True    <- (pack path) `regmatch` (concat (intersperse "|" badPackages))+               = msgDebug ("ignore known bad package " ++ path) >> return Nothing+  | True    <- buf `regmatch` "src = (fetchgit|sourceFromHead)"+               = msgDebug ("ignore non-hackage package " ++ path) >> return Nothing+  | True    <- buf `regmatch` "noHaddock"+               = msgDebug ("ignore non-haddock package " ++ path) >> return Nothing+  | True    <- buf =~ pack "cabal.mkDerivation"+  , [name]  <- buf `regsubmatch` "name *= *\"([^\"]+)\""+  , [vers]  <- buf `regsubmatch` "version *= *\"([^\"]+)\""+  , [sha]   <- buf `regsubmatch` "sha256 *= *\"([^\"]+)\""+  , plats   <- buf `regsubmatch` "platforms *= *([^;]+);"+  , maint   <- buf `regsubmatch` "maintainers *= *\\[([^\"]+)]"+              = let plats' = concatMap BS.words (map (BS.map (\c -> if c == '+' then ' ' else c)) plats)+                    maint' = concatMap BS.words maint+                in+                  return $ Just $ Pkg (unpack name)+                                      (unpack vers)+                                      (unpack sha)+                                      (map unpack plats')+                                      (map (normalizeMaintainer . unpack) maint')+                                      (path)+  | True <- buf `regmatch` "cabal.mkDerivation"+              = msgInfo ("failed to parse file " ++ path) >> return Nothing+  | otherwise = return Nothing++readVersion :: String -> Version+readVersion str =+  case [ v | (v,[]) <- readP_to_S parseVersion str ] of+    [ v' ] -> v'+    _      -> error ("invalid version specifier " ++ show str)++selectLatestVersions :: PkgSet -> PkgSet+selectLatestVersions = Set.fromList . nubBy f2 . sortBy f1 . Set.toList+  where+    f1 (Pkg n1 v1 _ _ _ _) (Pkg n2 v2 _ _ _ _)+      | n1 == n2  = compare v2 v1+      | otherwise = compare n1 n2+    f2 (Pkg n1 _ _ _ _ _) (Pkg n2 _ _ _ _ _)+      = n1 == n2++discoverUpdates :: PkgName -> PkgVersion -> Hackage4Nix [PkgVersion]+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 ]++updateNixPkgs :: [FilePath] -> Hackage4Nix ()+updateNixPkgs paths = do+  msgDebug $ "updating = " ++ show paths+  flip mapM_ paths $ \fileOrDir ->+    flip discoverNixFiles fileOrDir $ \file -> do+      nix' <- io (BS.readFile file) >>= parseNixFile file+      flip (maybe (return ())) nix' $ \nix -> do+        let Pkg name vers sha plats maints path = nix+            maints' = nub (sort (maints ++ ["andres","simons"]))+            plats'+              | null plats && not (null maints) = ["self.ghc.meta.platforms"]+              | otherwise                       = plats+        msgDebug ("re-generate " ++ path)+        when (null maints) (msgInfo ("warning: no maintainers configured for " ++ path))+        pkg <- readCabalFile name vers+        io $ writeFile path (showNixPkg (cabal2nix pkg sha plats' maints'))+        modify $ \cfg -> cfg { _pkgset = Set.insert nix (_pkgset cfg) }+  pkgset <- gets (selectLatestVersions . _pkgset)+  updates' <- flip mapM (Set.elems pkgset) $ \pkg -> do+    let Pkg name vers _ _ _ _ = pkg+    updates <- discoverUpdates name vers+    return (pkg,updates)+  let updates = [ u | u@(_,(_:_)) <- updates' ]+  when (not (null updates)) $ do+    msgInfo "The following updates are available:"+    flip mapM_ updates $ \(pkg,versions) -> do+      let Pkg name vers _ plats maints path = pkg+      msgInfo ""+      msgInfo $ name ++ "-" ++ vers ++ ":"+      flip mapM_ versions $ \newVersion -> do+        msgInfo $ "  " ++ genCabal2NixCmdline (Pkg name newVersion undefined plats maints path)+  return ()++genCabal2NixCmdline :: Pkg -> String+genCabal2NixCmdline (Pkg name vers _ plats maints path) = unwords $ ["cabal2nix"] ++ opts ++ [">"++path']+    where+      opts = [cabal] ++ maints' ++ plats'+      cabal = "cabal://" ++ name ++ "-" ++ vers+      maints' = [ "--maintainer=" ++ m | m <- maints ]+      plats'+        | ["self.ghc.meta.platforms"] == plats     = []+        | otherwise                                =  [ "--platform=" ++ p | p <- plats ]+      path'+        | pack path `regmatch` "/[0-9\\.]+\\.nix$" = replaceFileName path (vers <.> "nix")+        | otherwise                                = path++data CliOption = PrintHelp | Verbose | HackageDB FilePath+  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 []    ["hackage"]  (ReqArg HackageDB "HACKAGE-DIR")  "path to hackage database"+        ]++      usage :: String+      usage = usageInfo "Usage: hackage4nix [options] [dir-or-file ...]" options +++        "\n\+        \The purpose of 'hackage4nix' is to keep all Haskell packages in our\n\+        \repository packages up-to-date. It scans a checked-out copy of\n\+        \Nixpkgs for expressions that use 'cabal.mkDerivation', and\n\+        \re-generates them in-place with cabal2nix.\n\+        \\n\+        \Because we don't want to generate a barrage of HTTP requests during\n\+        \that procedure, the tool expects a copy of the Hackage database\n\+        \available at some local path, i.e. \"/dev/shm/hackage\" by default.\n\+        \That directory can be set up as follows:\n\+        \\n\+        \  cabal update\n\+        \  mkdir -p /dev/shm/hackage\n\+        \  tar xf ~/.cabal/packages/hackage.haskell.org/00-index.tar -C /dev/shm/hackage\n"++      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 "")++  let cfg = defaultConfiguration+            { _msgDebug  = if Verbose `elem` opts then _msgDebug defaultConfiguration else const (return ())+            , _hackageDb = last $ _hackageDb defaultConfiguration : [ p | HackageDB p <- opts ]+            }+  flip evalStateT cfg (updateNixPkgs args)++++-- Packages that we cannot regenerate automatically yet. This list+-- should be empty.++badPackages :: [String]+badPackages = [ "/"++p++"/" | p <- names ]+  where names =+          [ "alex"+          , "cairo"+          , "citeproc"+          , "citeproc-hs"+          , "editline"+          , "flapjax"+          , "ghc-events"+          , "glade"+          , "glib"+          , "glut"+          , "GLUT"+          , "gtk"+          , "gtksourceview2"+          , "haddock"+          , "haskell-platform"+          , "haskell-src"+          , "hfuse"+          , "hmatrix"+          , "hp2any-graph"+          , "idris"+          , "LambdaHack"+          , "lhs2tex"+          , "MazesOfMonad"+          , "OpenAL"+          , "OpenGL"+          , "pango"+          , "readline"+          , "repa-examples"+          , "scion"+          , "SDL"+          , "SDL-image"+          , "SDL-mixer"+          , "SDL-ttf"+          , "svgcairo"+          , "tar"+          , "terminfo"+          , "threadscope"+          , "vacuum"+          , "wxHaskell"+          , "X11"+          , "X11-xft"+          , "xmobar"+          ]