cabal2nix 1.12 → 1.13
raw patch · 8 files changed
+116/−202 lines, 8 filesdep +hackage-dbdep ~Cabaldep ~nixos-types
Dependencies added: hackage-db
Dependency ranges changed: Cabal, nixos-types
Files
- cabal2nix.cabal +8/−14
- src/Cabal2Nix.hs +1/−1
- src/Cabal2Nix/Flags.hs +11/−7
- src/Cabal2Nix/Generate.hs +54/−0
- src/Cabal2Nix/Package.hs +0/−53
- src/Cabal2Nix/PostProcess.hs +1/−0
- src/Hackage4Nix.hs +41/−54
- src/PackageList.hs +0/−73
cabal2nix.cabal view
@@ -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
src/Cabal2Nix.hs view
@@ -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
src/Cabal2Nix/Flags.hs view
@@ -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)
+ src/Cabal2Nix/Generate.hs view
@@ -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
− src/Cabal2Nix/Package.hs
@@ -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
src/Cabal2Nix/PostProcess.hs view
@@ -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
src/Hackage4Nix.hs view
@@ -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.
− src/PackageList.hs
@@ -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)