cabal2nix 1.8 → 1.9
raw patch · 7 files changed
+341/−3 lines, 7 files
Files
- cabal2nix.cabal +15/−3
- src/Cabal2Nix/CorePackages.hs +43/−0
- src/Cabal2Nix/Hackage.hs +43/−0
- src/Cabal2Nix/License.hs +21/−0
- src/Cabal2Nix/Name.hs +39/−0
- src/Cabal2Nix/Package.hs +138/−0
- src/Cabal2Nix/Pretty.hs +42/−0
cabal2nix.cabal view
@@ -1,5 +1,5 @@ Name: cabal2nix-Version: 1.8+Version: 1.9 Copyright: (c) 2011 Peter Simons and Andres Loeh License: BSD3 License-File: LICENSE@@ -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.8/cabal2nix.cabal- > cabal2nix cabal://cabal2nix-1.8+ > cabal2nix http://hackage.haskell.org/packages/archive/cabal2nix/1.9/cabal2nix.cabal+ > cabal2nix cabal://cabal2nix-1.9 . If the @--sha256@ option has not been specified, cabal2nix calls @nix-prefetch-url@ to determine the hash automatically. This causes@@ -46,6 +46,12 @@ hs-source-dirs: src Build-Depends: base >= 3 && < 5, Cabal, process, HTTP, pretty, filepath, directory Ghc-Options: -Wall+ other-modules: Cabal2Nix.Pretty+ Cabal2Nix.License+ Cabal2Nix.Name+ Cabal2Nix.CorePackages+ Cabal2Nix.Package+ Cabal2Nix.Hackage Executable hackage4nix main-is: Hackage4Nix.hs@@ -53,3 +59,9 @@ Build-Depends: base >= 3 && < 5, Cabal, pretty, filepath, directory, bytestring, regex-posix, mtl, containers Ghc-Options: -Wall+ other-modules: Cabal2Nix.Pretty+ Cabal2Nix.License+ Cabal2Nix.Name+ Cabal2Nix.CorePackages+ Cabal2Nix.Package+ Cabal2Nix.Hackage
+ src/Cabal2Nix/CorePackages.hs view
@@ -0,0 +1,43 @@+module Cabal2Nix.CorePackages ( corePackages, coreBuildTools ) where++-- | List of packages shipped with ghc and therefore at the moment not in+-- nixpkgs. This should probably be configurable at first. Later, it might+-- be good to actually include them as dependencies, but set them to null+-- if GHC provides them (as different GHC versions vary).+--+-- The commented packages have previously been non-core, so we don't filter+-- them.+corePackages :: [String]+corePackages = [+ "array",+ "base",+ "bin-package-db",+ "bytestring",+ "Cabal",+ "containers",+ "directory",+ -- "extensible-exceptions",+ "ffi",+ "filepath",+ "ghc",+ "ghc-binary",+ "ghc-prim",+ "haskell2010", -- new as core, but doesn't work in older GHCs anyway+ "haskell98",+ "hpc",+ "integer-gmp",+ "old-locale",+ "old-time",+ "pretty",+ "process",+ "random",+ "template-haskell",+ -- "time",+ "unix"+ ]++coreBuildTools :: [String]+coreBuildTools = [+ "ghc",+ "hsc2hs"+ ]
+ src/Cabal2Nix/Hackage.hs view
@@ -0,0 +1,43 @@+module Cabal2Nix.Hackage ( hackagePath, Ext(..), hashPackage ) where++import Distribution.Package ( PackageIdentifier(..), PackageName(..) )+import System.Process ( readProcess )+import System.Directory ( doesFileExist, getHomeDirectory, createDirectoryIfMissing )+import System.FilePath ( dropFileName, (</>), (<.>) )+import Data.Version ( showVersion )+import Control.Monad ( when )++data Ext = TarGz | Cabal deriving Eq++showExt :: Ext -> String+showExt TarGz = ".tar.gz"+showExt Cabal = ".cabal"++hackagePath :: PackageIdentifier -> Ext -> String+hackagePath (PackageIdentifier (PackageName name) version') ext =+ "http://hackage.haskell.org/packages/archive/" +++ name ++ "/" ++ version ++ "/" ++ name +++ (if ext == TarGz then "-" ++ version else "") +++ showExt ext+ where+ version = showVersion version'++hashPackage :: PackageIdentifier -> IO String+hashPackage pkg = do+ cachePath <- hashCachePath pkg+ exists <- doesFileExist cachePath+ hash' <- case exists of+ True -> readFile cachePath+ False -> readProcess "bash" ["-c", "exec nix-prefetch-url 2>/dev/tty " ++ hackagePath pkg TarGz] ""+ let hash = reverse (dropWhile (=='\n') (reverse hash'))+ when (not exists) $ do+ createDirectoryIfMissing True (dropFileName cachePath)+ writeFile cachePath hash+ return hash++hashCachePath :: PackageIdentifier -> IO FilePath+hashCachePath (PackageIdentifier (PackageName name) version') = do+ home <- getHomeDirectory+ return $ home ++ "/.cache/cabal2nix" </> name ++ "-" ++ version <.> "sha256"+ where+ version = showVersion version'
+ src/Cabal2Nix/License.hs view
@@ -0,0 +1,21 @@+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 = show "unknown"+showLic OtherLicense = show "unknown"+showLic l = error $ "unknown license: " ++ show l
+ src/Cabal2Nix/Name.hs view
@@ -0,0 +1,39 @@+module Cabal2Nix.Name ( toNixName, libNixName ) where++import Data.Char++toNixName :: String -> String+toNixName [] = error "toNixName: empty string is not a valid argument"+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++-- | Map libraries to Nix packages.+-- TODO: This should probably be configurable. We also need to consider the+-- possibility of name clashes with Haskell libraries. I have included+-- identity mappings to incicate that I have verified their correctness.+libNixName :: String -> [String]+libNixName "adns" = return "adns"+libNixName "cairo" = return "cairo"+libNixName "cairo-pdf" = return "cairo"+libNixName "cairo-ps" = return "cairo"+libNixName "cairo-svg" = return "cairo"+libNixName "crypto" = return "openssl"+libNixName "gnome-keyring" = return "gnome_keyring"+libNixName "gnome-keyring-1" = return "gnome_keyring"+libNixName "idn" = return "idn"+libNixName "libidn" = return "idn"+libNixName "libzip" = return "libzip"+libNixName "m" = [] -- in stdenv+libNixName "pcre" = return "pcre"+libNixName "pq" = return "postgresql"+libNixName "sndfile" = return "libsndfile"+libNixName "sqlite3" = return "sqlite"+libNixName "stdc++" = [] -- in stdenv+libNixName "xft" = return "libXft"+libNixName "X11" = return "libX11"+libNixName "z" = return "zlib"+libNixName x = return x
+ src/Cabal2Nix/Package.hs view
@@ -0,0 +1,138 @@+module Cabal2Nix.Package+ ( cabal2nix, showNixPkg+ , PkgName, PkgVersion, PkgSHA256, PkgURL, PkgDescription, PkgLicense+ , PkgIsLib, PkgIsExe, PkgDependencies, PkgBuildTools, PkgExtraLibs+ , PkgPkgconfigDeps, PkgPlatforms, PkgMaintainers+ )+ where++import Data.List+import Data.Maybe+import Distribution.Compiler+import Distribution.Package+import Distribution.PackageDescription+import Distribution.PackageDescription.Configuration+import Distribution.System+import Distribution.Version+import Text.PrettyPrint+import Data.Version ( showVersion )++import Cabal2Nix.License+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 = License+type PkgIsLib = Bool+type PkgIsExe = Bool+type PkgDependencies = [Dependency] -- [CondTree ConfVar [Dependency] ()]+type PkgBuildTools = [Dependency]+type PkgExtraLibs = [String]+type PkgPkgconfigDeps = [String]+type PkgPlatforms = [String]+type PkgMaintainers = [String]++data Pkg = Pkg PkgName+ PkgVersion+ PkgSHA256+ PkgURL+ PkgDescription+ PkgLicense+ PkgIsLib+ PkgIsExe+ PkgDependencies+ PkgBuildTools+ PkgExtraLibs+ PkgPkgconfigDeps+ PkgPlatforms+ PkgMaintainers+ deriving (Show)++showNixPkg :: Pkg -> String+showNixPkg (Pkg name ver sha256 url desc lic isLib isExe deps+ tools libs pcs 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,+ vcat [+ text "meta" <+> equals <+> lbrace,+ nest 2 $ vcat [+ onlyIf url $ attr "homepage" $ string url,+ onlyIf desc $ attr "description" $ string desc,+ attr "license" $ text (showLic 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+++cabal2nix :: GenericPackageDescription -> PkgSHA256 -> PkgPlatforms -> PkgMaintainers -> Pkg+cabal2nix cabal sha256 platforms maintainers =+ Pkg pkgname pkgver sha256 url desc lic+ isLib isExe+ (buildDepends tpkg)+ tools+ libs+ pcs+ [ 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 ]+ where+ pkg = packageDescription cabal+ PackageName pkgname = pkgName (package pkg)+ pkgver = showVersion (pkgVersion (package pkg))+ lic = license pkg+ url = homepage pkg+ desc = 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.+ Right (tpkg, _) = finalizePackageDescription [] (const True)+ (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
+ src/Cabal2Nix/Pretty.hs view
@@ -0,0 +1,42 @@+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+ ]