cabal2nix 1.10 → 1.11
raw patch · 10 files changed
+400/−281 lines, 10 filesdep ~Cabal
Dependency ranges changed: Cabal
Files
- cabal2nix.cabal +28/−13
- src/Cabal2Nix.hs +19/−10
- src/Cabal2Nix/License.hs +0/−21
- src/Cabal2Nix/Package.hs +48/−129
- src/Cabal2Nix/Pretty.hs +0/−42
- src/Distribution/NixOS/Derivation/Cabal.hs +106/−0
- src/Distribution/NixOS/Derivation/License.hs +54/−0
- src/Distribution/NixOS/Derivation/Meta.hs +39/−0
- src/Distribution/NixOS/Derivation/PrettyPrinting.hs +47/−0
- src/Hackage4Nix.hs +59/−66
cabal2nix.cabal view
@@ -1,5 +1,5 @@ Name: cabal2nix-Version: 1.10+Version: 1.11 Copyright: (c) 2011 Peter Simons and Andres Loeh License: BSD3 License-File: LICENSE@@ -41,28 +41,43 @@ Type: git Location: git://github.com/haskell4nix/cabal2nix.git +Library+ Build-Depends: base >= 3 && < 5, regex-posix, pretty, Cabal+ hs-source-dirs: src+ Extensions: PatternGuards+ Ghc-Options: -Wall+ Exposed-Modules: Distribution.NixOS.Derivation.Cabal+ Distribution.NixOS.Derivation.License+ Distribution.NixOS.Derivation.Meta+ other-modules: Distribution.NixOS.Derivation.PrettyPrinting+ Executable cabal2nix main-is: Cabal2Nix.hs hs-source-dirs: src- Build-Depends: base >= 3 && < 5, Cabal, process, HTTP, pretty, filepath, directory+ Build-Depends: base >= 3 && < 5, regex-posix, pretty, Cabal,+ filepath, directory, process, HTTP+ Extensions: PatternGuards Ghc-Options: -Wall- other-modules: Cabal2Nix.Pretty- Cabal2Nix.License+ other-modules: Cabal2Nix.CorePackages+ Cabal2Nix.Hackage Cabal2Nix.Name- Cabal2Nix.CorePackages Cabal2Nix.Package- Cabal2Nix.Hackage+ Distribution.NixOS.Derivation.Cabal+ Distribution.NixOS.Derivation.License+ Distribution.NixOS.Derivation.Meta+ Distribution.NixOS.Derivation.PrettyPrinting Executable hackage4nix main-is: Hackage4Nix.hs hs-source-dirs: src- Build-Depends: base >= 3 && < 5, Cabal >= 1.8, pretty, filepath, directory,- regex-posix, mtl, containers+ Build-Depends: base >= 3 && < 5, regex-posix, pretty, Cabal,+ mtl, containers, directory, filepath Extensions: PatternGuards- other-modules: Cabal2Nix.Pretty- Cabal2Nix.License+ Ghc-Options: -Wall+ other-modules: Cabal2Nix.CorePackages Cabal2Nix.Name- Cabal2Nix.CorePackages Cabal2Nix.Package- Cabal2Nix.Hackage-+ Distribution.NixOS.Derivation.Cabal+ Distribution.NixOS.Derivation.License+ Distribution.NixOS.Derivation.Meta+ Distribution.NixOS.Derivation.PrettyPrinting
src/Cabal2Nix.hs view
@@ -1,19 +1,21 @@ module Main ( main ) where import System.IO ( hPutStrLn, hFlush, stdout, stderr )-import System.Environment ( getArgs )+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 Distribution.Text 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.Package ( cabal2nix ) import Cabal2Nix.Hackage ( hackagePath, Ext(..), hashPackage )+import Distribution.NixOS.Derivation.Cabal+import Distribution.NixOS.Derivation.Meta readCabalFile :: FilePath -> IO String readCabalFile path@@ -60,11 +62,11 @@ let uri = args hash = [ h | SHA256 h <- opts ] noHaddock = NoHaddock `elem` 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'+ maints = [ if '.' `elem` m then m else "self.stdenv.lib.maintainers." ++ m | Maintainer m <- opts ]+ plats' = [ if '.' `elem` p then p else "self.stdenv.lib.platforms." ++ p | Platform p <- opts ]+ plats+ | null plats' = if not (null maints) then ["self.ghc.meta.platforms"] else []+ | otherwise = plats' when (length uri /= 1) (cmdlineError "*** exactly one URI must be specified") when (length hash > 1) (cmdlineError "*** the --sha256 option may be specified only once")@@ -78,6 +80,13 @@ let packageId = package (packageDescription cabal) - sha256 <- if null hash then hashPackage packageId else return (head hash)+ sha <- if null hash then hashPackage packageId else return (head hash) - putStr (showNixPkg (cabal2nix cabal sha256 noHaddock platforms maintainers))+ let deriv = (cabal2nix cabal) { sha256 = sha, runHaddock = not noHaddock }+ deriv' = deriv { metaSection = (metaSection deriv)+ { maintainers = maints+ , platforms = plats+ }+ }++ putStr (show (disp deriv'))
− src/Cabal2Nix/License.hs
@@ -1,21 +0,0 @@-module Cabal2Nix.License- (module Cabal2Nix.License, module Distribution.License)- where--import Distribution.License-import Distribution.Version--showLic :: License -> String-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 = "self.stdenv.lib.licenses.proprietary"-showLic OtherLicense = show "unknown"-showLic l = error $ "unknown license: " ++ show l
src/Cabal2Nix/Package.hs view
@@ -1,145 +1,55 @@-module Cabal2Nix.Package- ( cabal2nix, showNixPkg- , PkgName, PkgVersion, PkgSHA256, PkgURL, PkgDescription, PkgLicense- , PkgIsLib, PkgIsExe, PkgDependencies, PkgBuildTools, PkgExtraLibs- , PkgPkgconfigDeps, PkgPlatforms, PkgMaintainers, PkgNoHaddock, Pkg(..)- )- where+module Cabal2Nix.Package ( cabal2nix ) where -import Data.List import Data.Maybe import Distribution.Compiler-import Distribution.Package-import Distribution.PackageDescription+import qualified Distribution.Package as Cabal+import qualified Distribution.PackageDescription as Cabal import Distribution.PackageDescription.Configuration import Distribution.System import Distribution.Version-import Text.PrettyPrint-import Data.Version ( showVersion )--import Cabal2Nix.License+import Distribution.NixOS.Derivation.Cabal import Cabal2Nix.Name import Cabal2Nix.CorePackages-import Cabal2Nix.Pretty--type PkgName = String-type PkgVersion = String-type PkgSHA256 = String-type PkgURL = String-type PkgDescription = String-type PkgLicense = String-type PkgIsLib = Bool-type PkgIsExe = Bool-type PkgDependencies = [Dependency] -- [CondTree ConfVar [Dependency] ()]-type PkgBuildTools = [Dependency]-type PkgExtraLibs = [String]-type PkgPkgconfigDeps = [String]-type PkgNoHaddock = Bool-type PkgPlatforms = [String]-type PkgMaintainers = [String]--data Pkg = Pkg PkgName- PkgVersion- PkgSHA256- PkgURL- PkgDescription- PkgLicense- PkgIsLib- PkgIsExe- PkgDependencies- PkgBuildTools- PkgExtraLibs- PkgPkgconfigDeps- PkgNoHaddock- PkgPlatforms- PkgMaintainers- deriving (Show)--showNixPkg :: Pkg -> String-showNixPkg (Pkg name ver sha256 url desc lic isLib isExe deps- tools libs pcs noHaddock platforms maintainers) =- render doc- where- doc = funargs (map text ("cabal" : pkgInputs)) $$- vcat [- text "",- text "cabal.mkDerivation" <+> lparen <> text "self" <>- colon <+> lbrace,- nest 2 $ vcat [- attr "pname" $ string name,- attr "version" $ string ver,- attr "sha256" $ string sha256,- boolattr "isLibrary" (not isLib || isExe) isLib,- boolattr "isExecutable" (not isLib || isExe) isExe,- listattr "buildDepends" pkgDeps,- listattr "buildTools" pkgBuildTools,- listattr "extraLibraries" pkgLibs,- listattr "pkgconfigDepends" pkgPCs,- boolattr "noHaddock" noHaddock noHaddock,- vcat [- text "meta" <+> equals <+> lbrace,- nest 2 $ vcat [- onlyIf url $ attr "homepage" $ string url,- onlyIf desc $ attr "description" $ string desc,- attr "license" $ text lic,- onlyIf platforms $- sep [- text "platforms" <+> equals,- nest 2 ((fsep $ punctuate (text " ++") $ map text platforms)) <> semi- ],- listattr "maintainers" maintainers- ],- rbrace <> semi- ]- ],- rbrace <> rparen,- text ""- ]- pkgLibs = nub $ sort $ concatMap libNixName libs- pkgPCs = nub $ sort $ concatMap libNixName pcs- pkgDeps = nub $ sort $ map toNixName $- filter (`notElem` (name : corePackages)) $ map unDep deps- pkgBuildTools = nub $ sort $ map toNixName $- filter (`notElem` coreBuildTools) $ map unDep tools- pkgInputs = nub $ pkgLibs ++ pkgPCs ++ pkgBuildTools ++ pkgDeps-+import Data.List+import Data.Char -cabal2nix :: GenericPackageDescription -> PkgSHA256 -> PkgNoHaddock -> PkgPlatforms -> PkgMaintainers -> Pkg-cabal2nix cabal sha256 noHaddock platforms maintainers =- Pkg pkgname pkgver sha256 url desc lic- isLib isExe- (buildDepends tpkg)- tools- libs- pcs- noHaddock- [ if '.' `elem` p then p else "self.stdenv.lib.platforms." ++ p | p <- platforms ]- [ if '.' `elem` m then m else "self.stdenv.lib.maintainers." ++ m | m <- maintainers ]+cabal2nix :: Cabal.GenericPackageDescription -> Derivation+cabal2nix cabal = MkDerivation+ { pname = Cabal.pkgName pkg+ , version = Cabal.pkgVersion pkg+ , sha256 = "cabal2nix left the she256 field undefined"+ , isLibrary = isJust (Cabal.library tpkg)+ , isExecutable = not (null (Cabal.executables tpkg))+ , buildDepends = normalizeNixNames (filter (`notElem` (name : corePackages)) $ map unDep deps)+ , buildTools = normalizeNixNames (filter (`notElem` coreBuildTools) $ map unDep tools)+ , extraLibs = normalizeNixLibs libs+ , pkgConfDeps = normalizeNixLibs pcs+ , runHaddock = True+ , metaSection = Meta+ { homepage = Cabal.homepage descr+ , description = normalizeDescription (Cabal.synopsis descr)+ , license = fromCabalLicense (Cabal.license descr)+ , platforms = []+ , maintainers = []+ }+ } where- pkg = packageDescription cabal- PackageName pkgname = pkgName (package pkg)- pkgver = showVersion (pkgVersion (package pkg))- lic = showLic (license pkg)- url = homepage pkg- desc = normalizeDescription (synopsis pkg)- -- globalDeps = buildDepends pkg- -- Potentially dangerous: determine a default flattening of the- -- package description. Better approach: export the conditional- -- structure and reflect it in the generated file.+ descr = Cabal.packageDescription cabal+ pkg = Cabal.package descr+ Cabal.PackageName name = Cabal.pkgName pkg+ 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 [] (const True)- (Platform I386 Linux) -- shouldn't be hardcoded- (CompilerId GHC (Version [7,0,4] [])) -- dito+ (Platform I386 Linux) -- shouldn't be hardcoded+ (CompilerId GHC (Version [7,0,4] [])) -- dito [] cabal- isLib = isJust (library tpkg)- isExe = not (null (executables tpkg))- libDeps = map libBuildInfo $ maybeToList (library tpkg)- exeDeps = map buildInfo $ executables tpkg- libs = concatMap extraLibs (libDeps ++ exeDeps)- pcs = map unDep $ concatMap pkgconfigDepends (libDeps ++ exeDeps)- tools = concatMap buildTools (libDeps ++ exeDeps) -unDep :: Dependency -> String-unDep (Dependency (PackageName x) _) = x+unDep :: Cabal.Dependency -> String+unDep (Cabal.Dependency (Cabal.PackageName x) _) = x normalizeDescription :: String -> String normalizeDescription desc@@ -150,3 +60,12 @@ quote :: Char -> [Char] quote '"' = "\\\"" quote c = [c]++normalizeList :: [String] -> [String]+normalizeList = nub . sortBy (\x y -> compare (map toLower x) (map toLower y))++normalizeNixNames :: [String] -> [String]+normalizeNixNames = normalizeList . map toNixName++normalizeNixLibs :: [String] -> [String]+normalizeNixLibs = normalizeList . concatMap libNixName
− src/Cabal2Nix/Pretty.hs
@@ -1,42 +0,0 @@-module Cabal2Nix.Pretty where--import Text.PrettyPrint---- Pretty-printing helpers for Nix expressions.--attr :: String -> Doc -> Doc-attr n v = text n <+> equals <+> v <> semi--onlyIf :: [a] -> Doc -> Doc-onlyIf p d = if not (null p) then d else empty--boolattr :: String -> Bool -> Bool -> Doc-boolattr n p v = if p then attr n (bool v) else empty--listattr :: String -> [String] -> Doc-listattr n vs = onlyIf vs $- sep [ text n <+> equals <+> lbrack,- nest 2 $ fsep $ map text vs,- rbrack <> semi- ]--bool :: Bool -> Doc-bool True = text "true"-bool False = text "false"--string :: String -> Doc-string = doubleQuotes . text--version :: [Int] -> Doc-version = doubleQuotes . hcat . punctuate (text ".") . map int--prepunctuate :: Doc -> [Doc] -> [Doc]-prepunctuate _ [] = []-prepunctuate p (d:ds) = d : map (p <>) ds--funargs :: [Doc] -> Doc-funargs xs = sep [- lbrace <+> (fcat $ prepunctuate (comma <> text " ") $- map (nest 2) xs),- rbrace <> colon- ]
+ src/Distribution/NixOS/Derivation/Cabal.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE PatternGuards #-}++module Distribution.NixOS.Derivation.Cabal+ ( Derivation(..)+ , parseDerivation+ , module Distribution.NixOS.Derivation.Meta+ , Version(..), PackageName(..)+ )+ where++import Distribution.NixOS.Derivation.PrettyPrinting+import Distribution.NixOS.Derivation.Meta+import Distribution.Package+import Distribution.Text+import Data.Version+import Data.List+import Data.Char+import Text.PrettyPrint+import Text.ParserCombinators.ReadP ( readP_to_S )+import Text.Regex.Posix++data Derivation = MkDerivation+ { pname :: PackageName+ , version :: Version+ , sha256 :: String+ , isLibrary :: Bool+ , isExecutable :: Bool+ , buildDepends :: [String]+ , buildTools :: [String]+ , extraLibs :: [String]+ , pkgConfDeps :: [String]+ , runHaddock :: Bool+ , metaSection :: Meta+ }+ deriving (Show, Eq, Ord)++instance Text Derivation where+ disp = renderDerivation+ parse = error "parsing Distribution.NixOS.Derivation.Cabal.Derivation is not supported yet"++renderDerivation :: Derivation -> Doc+renderDerivation deriv = funargs (map text ("cabal" : inputs)) $$ vcat+ [ text ""+ , text "cabal.mkDerivation" <+> lparen <> text "self" <> colon <+> lbrace+ , nest 2 $ vcat+ [ attr "pname" $ doubleQuotes (disp (pname deriv))+ , attr "version" $ doubleQuotes (disp (version deriv))+ , attr "sha256" $ string (sha256 deriv)+ , boolattr "isLibrary" (not (isLibrary deriv) || (isExecutable deriv)) (isLibrary deriv)+ , boolattr "isExecutable" (not (isLibrary deriv) || (isExecutable deriv)) (isExecutable deriv)+ , listattr "buildDepends" (buildDepends deriv)+ , listattr "buildTools" (buildTools deriv)+ , listattr "extraLibraries" (extraLibs deriv)+ , listattr "pkgconfigDepends" (pkgConfDeps deriv)+ , boolattr "noHaddock" (not (runHaddock deriv)) (not (runHaddock deriv))+ , disp (metaSection deriv)+ ]+ , rbrace <> rparen+ , text ""+ ]+ where+ inputs = nub $ sortBy (\x y -> compare (map toLower x) (map toLower y)) $+ filter (/="cabal") $ filter (/="Cabal") $+ buildDepends deriv ++ buildTools deriv ++ extraLibs deriv ++ pkgConfDeps deriv++parseDerivation :: String -> Maybe Derivation+parseDerivation buf+ | buf =~ "cabal.mkDerivation"+ , [name] <- buf `regsubmatch` "pname *= *\"([^\"]+)\""+ , [vers] <- buf `regsubmatch` "version *= *\"([^\"]+)\""+ , [sha] <- buf `regsubmatch` "sha256 *= *\"([^\"]+)\""+ , plats <- buf `regsubmatch` "platforms *= *([^;]+);"+ , maint <- buf `regsubmatch` "maintainers *= *\\[([^\"]+)]"+ , noHaddock <- buf `regsubmatch` "noHaddock *= *(true|false) *;"+ = Just $ MkDerivation+ { pname = PackageName name+ , version = readVersion vers+ , sha256 = sha+ , isLibrary = False+ , isExecutable = False+ , buildDepends = []+ , buildTools = []+ , extraLibs = []+ , pkgConfDeps = []+ , runHaddock = case noHaddock of "true":[] -> False+ _ -> True+ , metaSection = Meta+ { homepage = ""+ , description = ""+ , license = Unknown Nothing+ , maintainers = concatMap words maint+ , platforms = concatMap words (map (map (\c -> if c == '+' then ' ' else c)) plats)+ }+ }+ | otherwise = Nothing++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++readVersion :: String -> Version+readVersion str =+ case [ v | (v,[]) <- readP_to_S parseVersion str ] of+ [ v' ] -> v'+ _ -> error ("invalid version specifier " ++ show str)
+ src/Distribution/NixOS/Derivation/License.hs view
@@ -0,0 +1,54 @@+module Distribution.NixOS.Derivation.License+ ( License(..)+ , fromCabalLicense+ )+ where++import qualified Distribution.License as Cabal ( License(..) )+import Data.Version ( Version(..) )+import Distribution.Text+import Text.PrettyPrint++data License+ = GPL2+ | GPL3+ | LGPL21+ | LGPL3+ | BSD3+ | BSD4+ | MIT+ | PublicDomain+ | Proprietary+ | Unknown (Maybe String)+ deriving (Eq, Ord)++instance Show License where+ show GPL2 = "self.stdenv.lib.licenses.gpl2"+ show GPL3 = "self.stdenv.lib.licenses.gpl3"+ show LGPL21 = "self.stdenv.lib.licenses.lgpl21"+ show LGPL3 = "self.stdenv.lib.licenses.gpl3"+ show BSD3 = "self.stdenv.lib.licenses.bsd3"+ show BSD4 = "self.stdenv.lib.licenses.bsd4"+ show MIT = "self.stdenv.lib.licenses.mit"+ show PublicDomain = "self.stdenv.lib.licenses.publicDomain"+ show Proprietary = "self.stdenv.lib.licenses.proprietary"+ show (Unknown lic) = show (maybe "unknown" id lic)++instance Text License where+ disp = text . show+ parse = error "parsing Distribution.NixOS.Derivation.License is not supported yet"++fromCabalLicense :: Cabal.License -> License+fromCabalLicense (Cabal.GPL Nothing) = Unknown (Just "GPL")+fromCabalLicense (Cabal.GPL (Just (Version [2] []))) = GPL2+fromCabalLicense (Cabal.GPL (Just (Version [3] []))) = GPL3+fromCabalLicense (Cabal.LGPL Nothing) = Unknown (Just "LGPL")+fromCabalLicense (Cabal.LGPL (Just (Version [2,1] []))) = LGPL21+fromCabalLicense (Cabal.LGPL (Just (Version [3] []))) = LGPL3+fromCabalLicense Cabal.BSD3 = BSD3+fromCabalLicense Cabal.BSD4 = BSD4+fromCabalLicense Cabal.MIT = MIT+fromCabalLicense Cabal.PublicDomain = PublicDomain+fromCabalLicense Cabal.AllRightsReserved = Proprietary+fromCabalLicense Cabal.OtherLicense = Unknown Nothing+fromCabalLicense l = error $ "Distribution.NixOS.Derivation.License.fromCabalLicense: unknown license " ++ show l
+ src/Distribution/NixOS/Derivation/Meta.hs view
@@ -0,0 +1,39 @@+module Distribution.NixOS.Derivation.Meta+ ( Meta(..)+ , module Distribution.NixOS.Derivation.License+ )+ where++import Distribution.NixOS.Derivation.PrettyPrinting+import Distribution.NixOS.Derivation.License+import Distribution.Text+import Text.PrettyPrint++data Meta = Meta+ { homepage :: String+ , description :: String+ , license :: License+ , platforms :: [String]+ , maintainers :: [String]+ }+ deriving (Show, Eq, Ord)++instance Text Meta where+ disp = renderMeta+ parse = error "parsing Distribution.NixOS.Derivation.Cabal.Meta is not supported yet"++renderMeta :: Meta -> Doc+renderMeta meta = vcat+ [ text "meta" <+> equals <+> lbrace+ , nest 2 $ vcat+ [ onlyIf (homepage meta) $ attr "homepage" $ string (homepage meta)+ , onlyIf (description meta) $ attr "description" $ string (description meta)+ , attr "license" $ disp (license meta)+ , onlyIf (platforms meta) $ sep+ [ text "platforms" <+> equals+ , nest 2 ((fsep $ punctuate (text " ++") $ map text (platforms meta))) <> semi+ ]+ , listattr "maintainers" (maintainers meta)+ ]+ , rbrace <> semi+ ]
+ src/Distribution/NixOS/Derivation/PrettyPrinting.hs view
@@ -0,0 +1,47 @@+module Distribution.NixOS.Derivation.PrettyPrinting+ ( onlyIf+ , listattr+ , boolattr+ , attr+ , string+ , funargs+ )+ where++import Text.PrettyPrint++-- Pretty-printing helpers for Nix expressions.++attr :: String -> Doc -> Doc+attr n v = text n <+> equals <+> v <> semi++onlyIf :: [a] -> Doc -> Doc+onlyIf p d = if not (null p) then d else empty++boolattr :: String -> Bool -> Bool -> Doc+boolattr n p v = if p then attr n (bool v) else empty++listattr :: String -> [String] -> Doc+listattr n vs = onlyIf vs $+ sep [ text n <+> equals <+> lbrack,+ nest 2 $ fsep $ map text vs,+ rbrack <> semi+ ]++bool :: Bool -> Doc+bool True = text "true"+bool False = text "false"++string :: String -> Doc+string = doubleQuotes . text++prepunctuate :: Doc -> [Doc] -> [Doc]+prepunctuate _ [] = []+prepunctuate p (d:ds) = d : map (p <>) ds++funargs :: [Doc] -> Doc+funargs xs = sep [+ lbrace <+> (fcat $ prepunctuate (comma <> text " ") $+ map (nest 2) xs),+ rbrace <> colon+ ]
src/Hackage4Nix.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE PatternGuards #-}- module Main ( main ) where import System.IO@@ -16,9 +14,15 @@ import Text.ParserCombinators.ReadP ( readP_to_S ) import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) ) import Distribution.PackageDescription ( GenericPackageDescription() )+import Distribution.Text import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )-import Cabal2Nix.Package ( cabal2nix, showNixPkg, PkgName, PkgVersion, PkgSHA256, PkgPlatforms, PkgMaintainers, PkgNoHaddock )+import Cabal2Nix.Package+import Distribution.NixOS.Derivation.Cabal+import Distribution.NixOS.Derivation.Meta +data Pkg = Pkg Derivation FilePath Bool+ deriving (Show, Eq, Ord)+ type PkgSet = Set.Set Pkg data Configuration = Configuration@@ -70,19 +74,15 @@ (True,_) -> return () (False,_) -> io (readDirectory dirOrFile) >>= mapM_ (discoverNixFiles yield . (dirOrFile </>)) -type Regenerate = Bool-data Pkg = Pkg PkgName PkgVersion PkgSHA256 PkgNoHaddock PkgPlatforms PkgMaintainers FilePath Regenerate- deriving (Show, Eq, Ord)--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+regenerateDerivation :: Derivation -> String -> Bool+regenerateDerivation deriv buf = not (display (pname deriv) `elem` patchedPackages) &&+ not (buf =~ "preConfigure|configureFlags|postInstall|patchPhase") -normalizeMaintainer :: String -> String-normalizeMaintainer x- | "self.stdenv.lib.maintainers." `isPrefixOf` x = drop 28 x- | otherwise = x+readVersion :: String -> Version+readVersion str =+ case [ v | (v,[]) <- readP_to_S parseVersion str ] of+ [ v' ] -> v'+ _ -> error ("invalid version specifier " ++ show str) parseNixFile :: FilePath -> String -> Hackage4Nix (Maybe Pkg) parseNixFile path buf@@ -92,46 +92,24 @@ = msgDebug ("ignore known bad package " ++ path) >> return Nothing | buf =~ "src = (fetchurl|fetchgit|sourceFromHead)" = msgDebug ("ignore non-hackage package " ++ path) >> return Nothing- | [name] <- buf `regsubmatch` "name *= *\"([^\"]+)\""- , [vers] <- buf `regsubmatch` "version *= *\"([^\"]+)\""- , [sha] <- buf `regsubmatch` "sha256 *= *\"([^\"]+)\""- , plats <- buf `regsubmatch` "platforms *= *([^;]+);"- , maint <- buf `regsubmatch` "maintainers *= *\\[([^\"]+)]"- , haddock <- buf `regsubmatch` "noHaddock *= *(true|false) *;"- = let plats' = concatMap words (map (map (\c -> if c == '+' then ' ' else c)) plats)- maint' = concatMap words maint- noHaddock- | "true":[] <- haddock = True- | otherwise = False- regenerate = not (name `elem` patchedPackages) &&- not (buf =~ "preConfigure|configureFlags|postInstall|patchPhase")- in- return $ Just $ Pkg name vers sha noHaddock plats'- (map normalizeMaintainer maint')- path regenerate+ | Just deriv <- parseDerivation buf+ = return (Just (Pkg deriv path (regenerateDerivation deriv buf))) | otherwise = msgInfo ("failed to parse file " ++ path) >> 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+ f1 (Pkg deriv1 _ _) (Pkg deriv2 _ _)+ | pname deriv1 == pname deriv2 = compare (version deriv2) (version deriv1)+ | otherwise = compare (pname deriv1) (pname deriv2)+ f2 (Pkg deriv1 _ _) (Pkg deriv2 _ _) = pname deriv1 == pname deriv2 -discoverUpdates :: PkgName -> PkgVersion -> Hackage4Nix [PkgVersion]+discoverUpdates :: String -> String -> Hackage4Nix [String] discoverUpdates name vers = do hackage <- gets _hackageDb versionStrings <- io $ readDirectory (hackage </> name) let versions = map readVersion versionStrings- return (sort [ showVersion v | v <- versions, v > readVersion vers ])+ return [ showVersion v | v <- versions, v > readVersion vers ] updateNixPkgs :: [FilePath] -> Hackage4Nix () updateNixPkgs paths = do@@ -140,45 +118,60 @@ flip discoverNixFiles fileOrDir $ \file -> do nix' <- io (readFile file) >>= parseNixFile file flip (maybe (return ())) nix' $ \nix -> do- let Pkg name vers sha noHaddock plats maints path regenerate = nix+ let Pkg deriv path regenerate = nix+ maints = maintainers (metaSection deriv)+ plats = platforms (metaSection deriv)+ when (null maints) (msgInfo ("no maintainers configured for " ++ path)) modify $ \cfg -> cfg { _pkgset = Set.insert nix (_pkgset cfg) } when regenerate $ do msgDebug ("re-generate " ++ path)- let maints' = nub (sort (maints ++ ["andres","simons"]))+ let maints' = nub (sort (maints ++ ["self.stdenv.lib.maintainers.andres","self.stdenv.lib.maintainers.simons"])) plats' | null plats && not (null maints) = ["self.ghc.meta.platforms"] | otherwise = plats- when (null maints) (msgInfo ("no maintainers configured for " ++ path))- pkg <- readCabalFile name vers- io $ writeFile path (showNixPkg (cabal2nix pkg sha noHaddock plats' maints'))+ pkg <- readCabalFile (display (pname deriv)) (display (version deriv))+ let deriv' = (cabal2nix pkg) { sha256 = sha256 deriv, runHaddock = runHaddock deriv }+ deriv'' = deriv' { metaSection = (metaSection deriv')+ { maintainers = maints'+ , platforms = plats'+ }+ }+ io $ writeFile path (show (disp deriv'')) pkgset <- gets (selectLatestVersions . _pkgset) updates' <- flip mapM (Set.elems pkgset) $ \pkg -> do- let Pkg name vers _ _ _ _ _ _ = pkg- updates <- discoverUpdates name vers+ let Pkg deriv _ _ = pkg+ updates <- discoverUpdates (display (pname deriv)) (display (version deriv)) 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 _ noHaddock plats maints path regenerate = pkg+ let Pkg deriv path regenerate = pkg msgInfo ""- msgInfo $ name ++ "-" ++ vers ++ ":"+ msgInfo $ (display (pname deriv)) ++ "-" ++ (display (version deriv)) ++ ":" flip mapM_ versions $ \newVersion -> do- msgInfo $ " " ++ genCabal2NixCmdline (Pkg name newVersion undefined noHaddock plats maints path regenerate)+ let deriv' = deriv { version = readVersion newVersion }+ msgInfo $ " " ++ genCabal2NixCmdline (Pkg deriv' path regenerate) return () genCabal2NixCmdline :: Pkg -> String-genCabal2NixCmdline (Pkg name vers _ noHaddock plats maints path _) = unwords $ ["cabal2nix"] ++ opts ++ [">"++path']- where- opts = [cabal] ++ maints' ++ plats' ++ if noHaddock then ["--no-haddock"] else []- cabal = "cabal://" ++ name ++ "-" ++ vers- maints' = [ "--maintainer=" ++ m | m <- maints ]- plats'- | ["self.ghc.meta.platforms"] == plats = []- | otherwise = [ "--platform=" ++ p | p <- plats ]- path'- | path =~ "/[0-9\\.]+\\.nix$" = replaceFileName path (vers <.> "nix")- | otherwise = path+genCabal2NixCmdline (Pkg deriv path _) = unwords $ ["cabal2nix"] ++ opts ++ [">"++path']+ where+ meta = metaSection deriv+ opts = [cabal] ++ maints' ++ plats' ++ if runHaddock deriv then [] else ["--no-haddock"]+ cabal = "cabal://" ++ display (pname deriv) ++ "-" ++ display (version deriv)+ maints' = [ "--maintainer=" ++ normalizeMaintainer m | m <- maintainers meta ]+ plats'+ | ["self.ghc.meta.platforms"] == platforms meta = []+ | otherwise = [ "--platform=" ++ p | p <- platforms meta ]+ path'+ | path =~ "/[0-9\\.]+\\.nix$" = replaceFileName path (display (version deriv) <.> "nix")+ | otherwise = path++normalizeMaintainer :: String -> String+normalizeMaintainer x+ | "self.stdenv.lib.maintainers." `isPrefixOf` x = drop 28 x+ | otherwise = x data CliOption = PrintHelp | Verbose | HackageDB FilePath deriving (Eq)