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 +41/−26
- cabal2nix.hs +0/−148
- src/Cabal2Nix.hs +81/−0
- src/Hackage4Nix.hs +294/−0
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"+ ]