git.iko.soy/typeable/cabal2nix
on master help sign in
hackage2nix: Add support for generating LTS Haskell package sets
603aec7Peter Simons
distribution-nixpkgs/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs+2
@@ -57,8 +57,10 @@ hooks =
57 , ("readline", over (libraryDepends . system) (Set.union (pkgs ["readline", "ncurses"])))
57 , ("readline", over (libraryDepends . system) (Set.union (pkgs ["readline", "ncurses"])))
58 , ("rocksdb-haskell", set (metaSection . platforms) (Set.singleton (Platform X86_64 Linux)))
58 , ("rocksdb-haskell", set (metaSection . platforms) (Set.singleton (Platform X86_64 Linux)))
59 , ("stack", set phaseOverrides stackPostInstall)
59 , ("stack", set phaseOverrides stackPostInstall)
60+ , ("stringbuilder", set doCheck False)
60 , ("target", set (testDepends . system . contains (pkg "z3")) True)
61 , ("target", set (testDepends . system . contains (pkg "z3")) True)
61 , ("terminfo", set (libraryDepends . system . contains (pkg "ncurses")) True)
62 , ("terminfo", set (libraryDepends . system . contains (pkg "ncurses")) True)
63+ , ("text", set doCheck False)
62 , ("thyme", set (libraryDepends . tool . contains (bind "self.cpphs")) True) -- required on Darwin
64 , ("thyme", set (libraryDepends . tool . contains (bind "self.cpphs")) True) -- required on Darwin
63 , ("xmonad", set phaseOverrides xmonadPostInstall)
65 , ("xmonad", set phaseOverrides xmonadPostInstall)
64 , ("wxc", wxcHook)
66 , ("wxc", wxcHook)
hackage2nix/src/Main.hs+75−44
@@ -7,6 +7,7 @@ import Control.Lens
7import Control.Monad
7import Control.Monad
8import Control.Monad.Par.Combinator
8import Control.Monad.Par.Combinator
9import Control.Monad.Par.IO
9import Control.Monad.Par.IO
10+import Control.Monad.Trans ( liftIO )
10import Data.List
11import Data.List
11import Data.Map.Strict ( Map )
12import Data.Map.Strict ( Map )
12import qualified Data.Map.Strict as Map
13import qualified Data.Map.Strict as Map
@@ -35,23 +36,13 @@ import Paths_hackage2nix as Config
35import Stackage
36import Stackage
36import System.FilePath
37import System.FilePath
37import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
38import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
39+import System.IO
38
40
39-- type Nixpkgs = PackageMap -- Map String (Set [String])
41-- type Nixpkgs = PackageMap -- Map String (Set [String])
40type PackageSet = Map String Version
42type PackageSet = Map String Version
41type PackageMultiSet = Map String (Set Version)
43type PackageMultiSet = Map String (Set Version)
42
44
43−resolveConstraint :: Constraint -> Hackage -> Version
45+data CLI = CLI
44−resolveConstraint c = fromMaybe (error msg) . resolveConstraint' c
45− where msg = "constraint " ++ display c ++ " cannot be resolved in Hackage"
46−
47−resolveConstraint' :: Constraint -> Hackage -> Maybe Version
48−resolveConstraint' (Dependency (PackageName name) vrange) hackage
49− | Just vset' <- Map.lookup name hackage
50− , vset <- Set.filter (`withinRange` vrange) (Map.keysSet vset')
51− , not (Set.null vset) = Just (Set.findMax vset)
52− | otherwise = Nothing
53−
54−data Options = Options
55 { hackageRepository :: FilePath
46 { hackageRepository :: FilePath
56 , preferredVersionsFile :: Maybe FilePath
47 , preferredVersionsFile :: Maybe FilePath
57 , nixpkgsRepository :: FilePath
48 , nixpkgsRepository :: FilePath
@@ -62,31 +53,30 @@ data Options = Options
62 }
53 }
63 deriving (Show)
54 deriving (Show)
64
55
65−options :: Parser Options
66−options = Options
67− <$> strOption (long "hackage" <> help "path to Hackage git repository" <> value "hackage" <> showDefaultWith id <> metavar "PATH")
68− <*> optional (strOption (long "preferred-versions" <> help "path to Hackage preferred-versions file" <> value "hackage/preferred-versions" <> showDefault <> metavar "PATH"))
69− <*> strOption (long "nixpkgs" <> help "path to Nixpkgs repository" <> value "nixpkgs" <> showDefaultWith id <> metavar "PATH")
70− <*> strOption (long "lts-haskell" <> help "path to LTS Haskell repository" <> value "lts-haskell" <> showDefaultWith id <> metavar "PATH")
71− <*> strOption (long "stackage-nightly" <> help "path to Stackage Nightly repository" <> value "stackage-nightly" <> showDefaultWith id <> metavar "PATH")
72− <*> strOption (long "config" <> help "path to configuration file" <> value "nixpkgs/pkgs/development/haskell-modules/configuration-hackage2nix.yaml" <> showDefaultWith id <> metavar "PATH")
73− <*> option (fmap fromString str) (long "platform" <> help "target platform to generate package set for" <> value "x86_64-linux" <> showDefaultWith display <> metavar "PLATFORM")
74−
75−pinfo :: ParserInfo Options
76−pinfo = info
77− ( helper
78− <*> infoOption ("hackage2nix " ++ display Config.version) (long "version" <> help "Show version number")
79− <*> options
80− )
81− ( fullDesc
82− <> header "hackage2nix converts a Hackage database into a haskell-packages.nix file."
83− )
84−
85main :: IO ()
56main :: IO ()
86main = do
57main = do
58+ let cliOptions :: Parser CLI
59+ cliOptions = CLI
60+ <$> strOption (long "hackage" <> help "path to Hackage git repository" <> value "hackage" <> showDefaultWith id <> metavar "PATH")
61+ <*> optional (strOption (long "preferred-versions" <> help "path to Hackage preferred-versions file" <> value "hackage/preferred-versions" <> showDefault <> metavar "PATH"))
62+ <*> strOption (long "nixpkgs" <> help "path to Nixpkgs repository" <> value "nixpkgs" <> showDefaultWith id <> metavar "PATH")
63+ <*> strOption (long "lts-haskell" <> help "path to LTS Haskell repository" <> value "lts-haskell" <> showDefaultWith id <> metavar "PATH")
64+ <*> strOption (long "stackage-nightly" <> help "path to Stackage Nightly repository" <> value "stackage-nightly" <> showDefaultWith id <> metavar "PATH")
65+ <*> strOption (long "config" <> help "path to configuration file inside of Nixpkgs" <> value "pkgs/development/haskell-modules/configuration-hackage2nix.yaml" <> showDefaultWith id <> metavar "PATH")
66+ <*> option (fmap fromString str) (long "platform" <> help "target platform to generate package set for" <> value "x86_64-linux" <> showDefaultWith display <> metavar "PLATFORM")
67+
68+ pinfo :: ParserInfo CLI
69+ pinfo = info
70+ ( helper
71+ <*> infoOption ("hackage2nix " ++ display Config.version) (long "version" <> help "Show version number")
72+ <*> cliOptions
73+ )
74+ ( fullDesc
75+ <> header "hackage2nix converts a Hackage database into a hackage-packages.nix file."
76+ )
87− Options {..} <- execParser pinfo
77+ CLI {..} <- execParser pinfo
88−
78+
89− config <- readConfiguration configFile
79+ config <- readConfiguration (nixpkgsRepository </> configFile)
90 nixpkgs <- readNixpkgPackageMap nixpkgsRepository Nothing
80 nixpkgs <- readNixpkgPackageMap nixpkgsRepository Nothing
91 preferredVersions <- readPreferredVersions (fromMaybe (hackageRepository </> "preferred-versions") preferredVersionsFile)
81 preferredVersions <- readPreferredVersions (fromMaybe (hackageRepository </> "preferred-versions") preferredVersionsFile)
92 let fixup = Map.delete "acme-everything" -- TODO: https://github.com/NixOS/cabal2nix/issues/164
82 let fixup = Map.delete "acme-everything" -- TODO: https://github.com/NixOS/cabal2nix/issues/164
@@ -96,6 +86,9 @@ main = do
96 hackage <- fixup <$> readHackage hackageRepository
86 hackage <- fixup <$> readHackage hackageRepository
97 snapshots <- runParIO (readStackage ltsHaskellRepository)
87 snapshots <- runParIO (readStackage ltsHaskellRepository)
98 let
88 let
89+ hackagePackagesFile :: FilePath
90+ hackagePackagesFile = nixpkgsRepository </> "pkgs/development/haskell-modules/hackage-packages.nix"
91+
99 corePackageSet :: PackageSet
92 corePackageSet :: PackageSet
100 corePackageSet = Map.fromList [ (name, v) | PackageIdentifier (PackageName name) v <- Set.toList (Config.corePackages config) ]
93 corePackageSet = Map.fromList [ (name, v) | PackageIdentifier (PackageName name) v <- Set.toList (Config.corePackages config) ]
101
94
@@ -141,12 +134,6 @@ main = do
141 globalPackageMaintainers :: Map PackageName (Set Identifier)
134 globalPackageMaintainers :: Map PackageName (Set Identifier)
142 globalPackageMaintainers = Map.unionsWith Set.union [ Map.singleton p (Set.singleton m) | (m,ps) <- Map.toList (packageMaintainers config), p <- Set.toList ps ]
135 globalPackageMaintainers = Map.unionsWith Set.union [ Map.singleton p (Set.singleton m) | (m,ps) <- Map.toList (packageMaintainers config), p <- Set.toList ps ]
143
136
144− do putStrLn "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"
145− putStrLn ""
146− putStrLn "{ pkgs, stdenv, callPackage }:"
147− putStrLn ""
148− putStrLn "self: {"
149− putStrLn ""
150 pkgs <- runParIO $ flip parMapM (Map.toAscList db) $ \(name, vs) -> do
137 pkgs <- runParIO $ flip parMapM (Map.toAscList db) $ \(name, vs) -> do
151 let defs = flip map (Set.toAscList vs) $ \v ->
138 let defs = flip map (Set.toAscList vs) $ \v ->
152 let
139 let
@@ -169,7 +156,7 @@ main = do
169 sha256 = fromMaybe (abort "has no hash") (lookup "X-Package-SHA256" (customFieldsPD (packageDescription descr)))
156 sha256 = fromMaybe (abort "has no hash") (lookup "X-Package-SHA256" (customFieldsPD (packageDescription descr)))
170
157
171 attr :: String
158 attr :: String
172− attr = name ++ if isInDefaultPackageSet then [] else '_' : [ if c == '.' then '_' else c | c <- display v ]
159+ attr = if isInDefaultPackageSet then name else mangle pkgId
173
160
174 drv :: Derivation
161 drv :: Derivation
175 drv = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr
162 drv = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr
@@ -184,8 +171,38 @@ main = do
184 render $ nest 2 $ hang (doubleQuotes (text attr) <+> equals <+> text "callPackage") 2 (parens (pPrint drv)) <+> (braces overrides <> semi)
171 render $ nest 2 $ hang (doubleQuotes (text attr) <+> equals <+> text "callPackage") 2 (parens (pPrint drv)) <+> (braces overrides <> semi)
185 return (intercalate "\n\n" defs)
172 return (intercalate "\n\n" defs)
186
173
174+ withFile hackagePackagesFile WriteMode $ \h -> do
175+ hPutStrLn h "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"
176+ hPutStrLn h ""
177+ hPutStrLn h "{ pkgs, stdenv, callPackage }:"
178+ hPutStrLn h ""
179+ hPutStrLn h "self: {"
180+ hPutStrLn h ""
187− mapM_ (\pkg -> putStrLn pkg >> putStrLn "") pkgs
181+ mapM_ (\pkg -> hPutStrLn h pkg >> hPutStrLn h "") pkgs
182+ hPutStrLn h "}"
183+
184+ void $ runParIO $ flip parMapM snapshots $ \Snapshot {..} -> liftIO $ do
185+ let ltsConfigFile :: FilePath
186+ ltsConfigFile = nixpkgsRepository </> "pkgs/development/haskell-modules/configuration-" ++ show (pPrint snapshot) ++ ".nix"
188− putStrLn "}"
187+ putStrLn ("writing " ++ ltsConfigFile)
188+ withFile ltsConfigFile WriteMode $ \h -> do
189+ hPutStrLn h "{ pkgs }:"
190+ hPutStrLn h ""
191+ hPutStrLn h ("self: super: assert super.ghc.name == " ++ show (display compiler) ++ "; {")
192+ hPutStrLn h ""
193+ hPutStrLn h " # core libraries provided by the compiler"
194+ forM_ (Map.keys (Map.insert (PackageName "rts") (Version [] []) (Map.insert (PackageName "Cabal") (Version [] []) corePackages))) $ \(PackageName n) -> do
195+ unless (n == "ghc") (hPutStrLn h (" " ++ n ++ " = null;"))
196+ hPutStrLn h ""
197+ hPutStrLn h (" # " ++ show (pPrint snapshot) ++ " packages")
198+ forM_ (Map.toList packages) $ \(PackageName name, spec) -> do
199+ let isInDefaultPackageSet :: Bool
200+ isInDefaultPackageSet = maybe False (== Stackage.version spec) (Map.lookup name generatedDefaultPackageSet)
201+ unless (isInDefaultPackageSet || name `elem` ["Cabal","rts"]) $
202+ hPutStrLn h (" " ++ show name ++ " = super." ++ show (mangle (PackageIdentifier (PackageName name) (Stackage.version spec))) ++ ";")
203+ hPutStrLn h ""
204+ hPutStrLn h "}"
205+
189
206
190isFromHackage :: Binding -> Bool
207isFromHackage :: Binding -> Bool
191isFromHackage b = case view (reference . path) b of
208isFromHackage b = case view (reference . path) b of
@@ -203,3 +220,17 @@ parsePreferredVersionsLine l = simpleParse l `mplus` error ("invalid preferred-v
203enforcePreferredVersions :: [Constraint] -> String -> Map Version GenericPackageDescription
220enforcePreferredVersions :: [Constraint] -> String -> Map Version GenericPackageDescription
204 -> Map Version GenericPackageDescription
221 -> Map Version GenericPackageDescription
205enforcePreferredVersions cs pkg = Map.filterWithKey (\v _ -> PackageIdentifier (PackageName pkg) v `satisfiesConstraints` cs)
222enforcePreferredVersions cs pkg = Map.filterWithKey (\v _ -> PackageIdentifier (PackageName pkg) v `satisfiesConstraints` cs)
223+
224+resolveConstraint :: Constraint -> Hackage -> Version
225+resolveConstraint c = fromMaybe (error msg) . resolveConstraint' c
226+ where msg = "constraint " ++ display c ++ " cannot be resolved in Hackage"
227+
228+resolveConstraint' :: Constraint -> Hackage -> Maybe Version
229+resolveConstraint' (Dependency (PackageName name) vrange) hackage
230+ | Just vset' <- Map.lookup name hackage
231+ , vset <- Set.filter (`withinRange` vrange) (Map.keysSet vset')
232+ , not (Set.null vset) = Just (Set.findMax vset)
233+ | otherwise = Nothing
234+
235+mangle :: PackageIdentifier -> String
236+mangle (PackageIdentifier (PackageName name) v) = name ++ '_' : [ if c == '.' then '_' else c | c <- display v ]