git.iko.soy/typeable/cabal2nix
on master help sign in
hackage2nix: add all Stackage packages to the package set

The generated haskell-packages.nix file now contains everything needed to configure all known versions of LTS Haskell. The only bit missing at the moment is the code that generates the appropriate configuration-lts-x.y.nix files.

commit0356aa76d535985e8af3b5303094b70a2a0a70be authorPeter Simons <simons@cryp.to> dateMon 14 Sep 2015, 13:53 (11 years ago) parenta06232e
4 files changed+161−457
hackage2nix/hackage2nix.cabal+1 hackage2nix/package.yaml+1 hackage2nix/src/Main.hs+112−432 hackage2nix/src/Stackage.hs+47−25
hackage2nix/hackage2nix.cabal+1
@@ -42,6 +42,7 @@ executable hackage2nix
4242 , optparse-applicative
4343 , pretty >= 1.1.2
4444 , SHA
45+ , split
4546 , stackage-types
4647 , text
4748 , time
hackage2nix/package.yaml+1
@@ -27,6 +27,7 @@ dependencies:
2727 - optparse-applicative
2828 - pretty >= 1.1.2
2929 - SHA
30+ - split
3031 - stackage-types
3132 - text
3233 - time
hackage2nix/src/Main.hs+112−432
@@ -7,7 +7,6 @@ import Control.Lens
77import Control.Monad
88import Control.Monad.Par.Combinator
99import Control.Monad.Par.IO
10−import Control.Monad.Trans ( liftIO )
1110import Data.List
1211import Data.Map.Strict ( Map )
1312import qualified Data.Map.Strict as Map
@@ -19,10 +18,9 @@ import Data.String
1918import Distribution.Nixpkgs.Fetch
2019import Distribution.Nixpkgs.Haskell
2120import Distribution.Nixpkgs.Haskell.Constraint
22−import Distribution.Nixpkgs.Haskell.FromCabal ( fromGenericPackageDescription )
23−import Distribution.Nixpkgs.Haskell.FromCabal.Configuration
21+import Distribution.Nixpkgs.Haskell.FromCabal
22+import Distribution.Nixpkgs.Haskell.FromCabal.Configuration as Config
2423import Distribution.Nixpkgs.Haskell.FromCabal.Flags
25−import Distribution.Nixpkgs.Haskell.PackageSourceSpec
2624import Distribution.Nixpkgs.Meta
2725import Distribution.Nixpkgs.PackageMap
2826import Distribution.Package
@@ -33,11 +31,12 @@ import Distribution.Version
3331import HackageGit ( readHackage, Hackage )
3432import Language.Nix
3533import Options.Applicative
36−import Paths_hackage2nix
34+import Paths_hackage2nix as Config
35+import Stackage
3736import System.FilePath
3837import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
3938
40−type Nixpkgs = PackageMap -- Map String (Set [String])
39+-- type Nixpkgs = PackageMap -- Map String (Set [String])
4140type PackageSet = Map String Version
4241type PackageMultiSet = Map String (Set Version)
4342
@@ -56,6 +55,8 @@ data Options = Options
5655 { hackageRepository :: FilePath
5756 , preferredVersionsFile :: Maybe FilePath
5857 , nixpkgsRepository :: FilePath
58+ , ltsHaskellRepository :: FilePath
59+ , stackageNightlyRepository :: FilePath
5960 , configFile :: FilePath
6061 , targetPlatform :: Platform
6162 }
@@ -65,14 +66,16 @@ options :: Parser Options
6566options = Options
6667 <$> strOption (long "hackage" <> help "path to Hackage git repository" <> value "hackage" <> showDefaultWith id <> metavar "PATH")
6768 <*> optional (strOption (long "preferred-versions" <> help "path to Hackage preferred-versions file" <> value "hackage/preferred-versions" <> showDefault <> metavar "PATH"))
68− <*> strOption (long "nixpkgs" <> help "path to Nixpkgs repository" <> value "<nixpkgs>" <> showDefaultWith id <> 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")
6972 <*> strOption (long "config" <> help "path to configuration file" <> value "nixpkgs/pkgs/development/haskell-modules/configuration-hackage2nix.yaml" <> showDefaultWith id <> metavar "PATH")
7073 <*> option (fmap fromString str) (long "platform" <> help "target platform to generate package set for" <> value "x86_64-linux" <> showDefaultWith display <> metavar "PLATFORM")
7174
7275pinfo :: ParserInfo Options
7376pinfo = info
7477 ( helper
75− <*> infoOption ("hackage2nix " ++ display version) (long "version" <> help "Show version number")
78+ <*> infoOption ("hackage2nix " ++ display Config.version) (long "version" <> help "Show version number")
7679 <*> options
7780 )
7881 ( fullDesc
@@ -83,114 +86,111 @@ main :: IO ()
8386main = do
8487 Options {..} <- execParser pinfo
8588
86− defaultConfiguration <- readConfiguration configFile
87− hackage <- readHackage hackageRepository
89+ config <- readConfiguration configFile
8890 nixpkgs <- readNixpkgPackageMap nixpkgsRepository Nothing
8991 preferredVersions <- readPreferredVersions (fromMaybe (hackageRepository </> "preferred-versions") preferredVersionsFile)
9092 let fixup = Map.delete "acme-everything" -- TODO: https://github.com/NixOS/cabal2nix/issues/164
9193 . Map.delete "som" -- TODO: https://github.com/NixOS/cabal2nix/issues/164
9294 . Map.delete "type" -- TODO: https://github.com/NixOS/cabal2nix/issues/163
9395 . Map.delete "dictionary-sharing" -- TODO: https://github.com/NixOS/cabal2nix/issues/175
94− . Map.filter (/= Map.empty)
95− . Map.mapWithKey (enforcePreferredVersions preferredVersions)
96− runParIO $ generatePackageSet targetPlatform defaultConfiguration (fixup hackage) nixpkgs
97−
98−enforcePreferredVersions :: [Constraint] -> String -> Map Version GenericPackageDescription
99− -> Map Version GenericPackageDescription
100−enforcePreferredVersions cs pkg = Map.filterWithKey (\v _ -> PackageIdentifier (PackageName pkg) v `satisfiesConstraints` cs)
101−
102−generatePackageSet :: Platform -> Configuration -> Hackage -> Nixpkgs -> ParIO ()
103−generatePackageSet targetPlatform config hackage nixpkgs = do
96+ hackage <- fixup <$> readHackage hackageRepository
97+ snapshots <- runParIO (readStackage ltsHaskellRepository)
10498 let
105− corePackageSet :: PackageSet
106− corePackageSet = Map.fromList [ (name, v) | PackageIdentifier (PackageName name) v <- Set.toList (corePackages config) ]
107−
108− latestVersionSet :: PackageSet
109− latestVersionSet = Map.map (Set.findMax . Map.keysSet) hackage
110−
111− defaultPackageOverridesSet :: PackageSet
112− defaultPackageOverridesSet = Map.fromList [ (name, resolveConstraint c hackage) | c@(Dependency (PackageName name) _) <- defaultPackageOverrides config ]
113−
114− generatedDefaultPackageSet :: PackageSet
115− generatedDefaultPackageSet = (defaultPackageOverridesSet `Map.union` latestVersionSet) `Map.difference` corePackageSet
116−
117− latestCorePackageSet :: PackageSet
118− latestCorePackageSet = latestVersionSet `Map.intersection` corePackageSet
119−
120− latestOverridePackageSet :: PackageSet
121− latestOverridePackageSet = latestVersionSet `Map.intersection` defaultPackageOverridesSet
122−
123− extraPackageSet :: PackageMultiSet
124− extraPackageSet = Map.unionsWith Set.union
125− [ Map.singleton name (Set.singleton (resolveConstraint c hackage)) | c@(Dependency (PackageName name) _) <- extraPackages config ]
126−
127− db :: PackageMultiSet
128− db = Map.unionsWith Set.union [ Map.map Set.singleton generatedDefaultPackageSet
129− , Map.map Set.singleton latestCorePackageSet
130− , Map.map Set.singleton latestOverridePackageSet
131− , extraPackageSet
132− ]
133−
134− haskellResolver :: Dependency -> Bool
135− haskellResolver (Dependency (PackageName name) vrange)
136− | Just v <- Map.lookup name corePackageSet = v `withinRange` vrange
137− | Just v <- Map.lookup name generatedDefaultPackageSet = v `withinRange` vrange
138− | otherwise = False
139−
140− nixpkgsResolver :: Identifier -> Maybe Binding
141− nixpkgsResolver = resolve (Map.map (Set.map (over path ("pkgs":))) nixpkgs)
142−
143− globalPackageMaintainers :: Map PackageName (Set Identifier)
144− globalPackageMaintainers = Map.unionsWith Set.union [ Map.singleton p (Set.singleton m) | (m,ps) <- Map.toList (packageMaintainers config), p <- Set.toList ps ]
145−
146− liftIO $ do putStrLn "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"
147− putStrLn ""
148− putStrLn "{ pkgs, stdenv, callPackage }:"
149− putStrLn ""
150− putStrLn "self: {"
151− putStrLn ""
152− pkgs <- flip parMapM (Map.toAscList db) $ \(name, vs) -> do
153− defs <- forM (Set.toAscList vs) $ \pkgversion -> do
154− let -- TODO: Include list of broken dependencies in the generated output.
155− descr = hackage Map.! name Map.! pkgversion
156−
157− flagAssignment :: FlagAssignment
158− flagAssignment = configureCabalFlags (packageId descr)
159−
160− drv' :: Derivation
161− drv' = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr
162−
163− isInDefaultPackageSet :: Bool
164− isInDefaultPackageSet = maybe False (== pkgversion) (Map.lookup name generatedDefaultPackageSet)
165−
166− attr :: String
167− attr = name ++ if isInDefaultPackageSet then [] else '_' : [ if c == '.' then '_' else c | c <- display pkgversion ]
168−
169− sha256 :: String
170− sha256 | Just x <- lookup "X-Package-SHA256" (customFieldsPD (packageDescription descr)) = x
171− | otherwise = error $ display (packageId descr) ++ " has no hash"
172−
173− srcSpec <- liftIO $ sourceFromHackage (Certain sha256) (name ++ "-" ++ display pkgversion)
174−
175− let drv = drv' & src .~ srcSpec
176− & metaSection.hydraPlatforms %~ (`Set.difference` fromMaybe Set.empty (Map.lookup (PackageName name) (dontDistributePackages config)))
177− & metaSection.hydraPlatforms %~ (if isInDefaultPackageSet then id else const Set.empty)
178− & metaSection.maintainers .~ fromMaybe Set.empty (Map.lookup (PackageName name) globalPackageMaintainers)
179−
180− isFromHackage :: Binding -> Bool
181− isFromHackage b = case view (reference . path) b of
182− ["self",_] -> True
183− _ -> False
184−
185− overrides :: Doc
186− overrides = fcat $ punctuate space
187− [ pPrint b | b <- Set.toList (view (dependencies . each) drv), not (isFromHackage b) ]
188−
189− return $ nest 2 $ hang (doubleQuotes (text attr) <+> equals <+> text "callPackage") 2 (parens (pPrint drv)) <+> (braces overrides <> semi)
190− return (intercalate "\n\n" (map render defs))
191−
192− liftIO $ mapM_ (\pkg -> putStrLn pkg >> putStrLn "") pkgs
193− liftIO $ putStrLn "}"
99+ corePackageSet :: PackageSet
100+ corePackageSet = Map.fromList [ (name, v) | PackageIdentifier (PackageName name) v <- Set.toList (Config.corePackages config) ]
101+
102+ latestVersionSet :: PackageSet
103+ latestVersionSet = Map.map (Set.findMax . Map.keysSet) (Map.filter (/= Map.empty) (Map.mapWithKey (enforcePreferredVersions preferredVersions) hackage))
104+
105+ defaultPackageOverridesSet :: PackageSet
106+ defaultPackageOverridesSet = Map.fromList [ (name, resolveConstraint c hackage) | c@(Dependency (PackageName name) _) <- defaultPackageOverrides config ]
107+
108+ generatedDefaultPackageSet :: PackageSet
109+ generatedDefaultPackageSet = (defaultPackageOverridesSet `Map.union` latestVersionSet) `Map.difference` corePackageSet
110+
111+ latestCorePackageSet :: PackageSet
112+ latestCorePackageSet = latestVersionSet `Map.intersection` corePackageSet
113+
114+ latestOverridePackageSet :: PackageSet
115+ latestOverridePackageSet = latestVersionSet `Map.intersection` defaultPackageOverridesSet
116+
117+ extraPackageSet :: PackageMultiSet
118+ extraPackageSet = Map.unionsWith Set.union
119+ [ Map.singleton name (Set.singleton (resolveConstraint c hackage)) | c@(Dependency (PackageName name) _) <- extraPackages config ]
120+
121+ stackagePackageSet :: PackageMultiSet
122+ stackagePackageSet = Map.fromListWith Set.union [ (unPackageName n, Set.singleton (Stackage.version spec)) | snapshot <- snapshots, (n, spec) <- Map.toList (packages snapshot) ]
123+
124+ db :: PackageMultiSet
125+ db = Map.unionsWith Set.union [ Map.map Set.singleton generatedDefaultPackageSet
126+ , Map.map Set.singleton latestCorePackageSet
127+ , Map.map Set.singleton latestOverridePackageSet
128+ , extraPackageSet
129+ , stackagePackageSet
130+ ]
131+
132+ haskellResolver :: Dependency -> Bool
133+ haskellResolver (Dependency (PackageName name) vrange)
134+ | Just v <- Map.lookup name corePackageSet = v `withinRange` vrange
135+ | Just v <- Map.lookup name generatedDefaultPackageSet = v `withinRange` vrange
136+ | otherwise = False
137+
138+ nixpkgsResolver :: Identifier -> Maybe Binding
139+ nixpkgsResolver = resolve (Map.map (Set.map (over path ("pkgs":))) nixpkgs)
140+
141+ 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 ]
143+
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
151+ let defs = flip map (Set.toAscList vs) $ \v ->
152+ let
153+ pkgId :: PackageIdentifier
154+ pkgId = PackageIdentifier (PackageName name) v
155+
156+ isInDefaultPackageSet :: Bool
157+ isInDefaultPackageSet = maybe False (== v) (Map.lookup name generatedDefaultPackageSet)
158+
159+ abort :: String -> a
160+ abort msg = error (display pkgId ++ ": " ++ msg)
161+
162+ descr :: GenericPackageDescription
163+ descr = fromMaybe (abort "not on Hackage") (Map.lookup name hackage >>= Map.lookup v)
164+
165+ flagAssignment :: FlagAssignment
166+ flagAssignment = configureCabalFlags (packageId descr)
167+
168+ sha256 :: String
169+ sha256 = fromMaybe (abort "has no hash") (lookup "X-Package-SHA256" (customFieldsPD (packageDescription descr)))
170+
171+ attr :: String
172+ attr = name ++ if isInDefaultPackageSet then [] else '_' : [ if c == '.' then '_' else c | c <- display v ]
173+
174+ drv :: Derivation
175+ drv = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr
176+ & src .~ DerivationSource "url" ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") "" sha256
177+ & metaSection.hydraPlatforms %~ (`Set.difference` fromMaybe Set.empty (Map.lookup (PackageName name) (dontDistributePackages config)))
178+ & metaSection.maintainers .~ fromMaybe Set.empty (Map.lookup (PackageName name) globalPackageMaintainers)
179+ & metaSection.hydraPlatforms %~ (if isInDefaultPackageSet then id else const Set.empty)
180+
181+ overrides :: Doc
182+ overrides = fcat $ punctuate space [ pPrint b | b <- Set.toList (view (dependencies . each) drv), not (isFromHackage b) ]
183+ in
184+ render $ nest 2 $ hang (doubleQuotes (text attr) <+> equals <+> text "callPackage") 2 (parens (pPrint drv)) <+> (braces overrides <> semi)
185+ return (intercalate "\n\n" defs)
186+
187+ mapM_ (\pkg -> putStrLn pkg >> putStrLn "") pkgs
188+ putStrLn "}"
189+
190+isFromHackage :: Binding -> Bool
191+isFromHackage b = case view (reference . path) b of
192+ ["self",_] -> True
193+ _ -> False
194194
195195readPreferredVersions :: FilePath -> IO [Constraint]
196196readPreferredVersions p = mapMaybe parsePreferredVersionsLine . lines <$> readFile p
@@ -200,326 +200,6 @@ parsePreferredVersionsLine [] = Nothing
200200parsePreferredVersionsLine ('-':'-':_) = Nothing
201201parsePreferredVersionsLine l = simpleParse l `mplus` error ("invalid preferred-versions line: " ++ show l)
202202
203−
204−
205−-- {-# LANGUAGE OverloadedStrings #-}
206−-- {-# LANGUAGE RecordWildCards #-}
207−--
208−-- module Main ( main ) where
209−--
210−-- import Control.Lens
211−-- -- import Control.Exception
212−-- import Control.Monad
213−-- import Control.Monad.Par.Combinator
214−-- import Control.Monad.Par.IO as ParIO
215−-- import Control.Monad.Par as Par
216−-- -- import Control.Monad.Trans ( liftIO )
217−-- -- import Data.List
218−-- import Data.Map.Strict ( Map )
219−-- import qualified Data.Map.Strict as Map
220−-- import Data.Maybe
221−-- import Data.Monoid
222−-- import Data.Set ( Set )
223−-- import qualified Data.Set as Set
224−-- import Data.String
225−-- import Distribution.Compiler
226−-- import Distribution.Nixpkgs.Fetch
227−-- import Distribution.Nixpkgs.Haskell
228−-- -- import Distribution.Nixpkgs.Haskell.Constraint
229−-- import Distribution.Nixpkgs.Haskell.FromCabal ( fromGenericPackageDescription )
230−-- -- import Distribution.Nixpkgs.Haskell.FromCabal.Configuration
231−-- -- import Distribution.Nixpkgs.Haskell.FromCabal.Flags
232−-- import Distribution.Nixpkgs.Haskell.HackageGit ( readHackage, Hackage )
233−-- -- import Distribution.Nixpkgs.Haskell.PackageSourceSpec
234−-- -- import Distribution.Nixpkgs.Meta
235−-- import Distribution.Nixpkgs.PackageMap
236−-- import Distribution.Package
237−-- import Distribution.PackageDescription hiding ( options, buildDepends, extraLibs, buildTools )
238−-- import Distribution.System
239−-- import Distribution.Text
240−-- import Distribution.Version
241−-- import Language.Nix
242−-- import Options.Applicative
243−-- import qualified Paths_hackage2nix as Main
244−-- import System.FilePath
245−-- import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
246−-- import Stackage
247−-- import System.IO
248−--
249−-- -- type Nixpkgs = PackageMap -- Map String (Set [String])
250−-- -- type PackageSet = Map PackageName Version
251−-- -- type PackageMultiSet = Map String (Set Version)
252−-- --
253−-- -- resolveConstraint :: Constraint -> Hackage -> Version
254−-- -- resolveConstraint c = fromMaybe (error msg) . resolveConstraint' c
255−-- -- where msg = "constraint " ++ display c ++ " cannot be resolved in Hackage"
256−-- --
257−-- -- resolveConstraint' :: Constraint -> Hackage -> Maybe Version
258−-- -- resolveConstraint' (Dependency (PackageName name) vrange) hackage
259−-- -- | Just vset' <- Map.lookup name hackage
260−-- -- , vset <- Set.filter (`withinRange` vrange) (Map.keysSet vset')
261−-- -- , not (Set.null vset) = Just (Set.findMax vset)
262−-- -- | otherwise = Nothing
263−--
264−-- data Options = Options
265−-- { hackageRepository :: FilePath
266−-- , preferredVersionsFile :: Maybe FilePath
267−-- , nixpkgsRepository :: FilePath
268−-- , ltsHaskellRepository :: FilePath
269−-- , stackageNightlyRepository :: FilePath
270−-- , configFile :: FilePath
271−-- , targetPlatform :: Platform
272−-- }
273−-- deriving (Show)
274−--
275−-- options :: Parser Options
276−-- options = Options
277−-- <$> strOption (long "hackage" <> help "path to Hackage git repository" <> value "hackage" <> showDefaultWith id <> metavar "PATH")
278−-- <*> optional (strOption (long "preferred-versions" <> help "path to Hackage preferred-versions file" <> value "hackage/preferred-versions" <> showDefault <> metavar "PATH"))
279−-- <*> strOption (long "nixpkgs" <> help "path to Nixpkgs repository" <> value "/home/simons/src/cabal2nix/hackage2nix/nixpkgs" <> showDefaultWith id <> metavar "PATH")
280−-- <*> strOption (long "lts-haskell" <> help "path to LTS Haskell repository" <> value "lts-haskell" <> showDefaultWith id <> metavar "PATH")
281−-- <*> strOption (long "stackage-nightly" <> help "path to Stackage Nightly repository" <> value "stackage-nightly" <> showDefaultWith id <> metavar "PATH")
282−-- <*> strOption (long "config" <> help "path to configuration file" <> value "nixpkgs/pkgs/development/haskell-modules/configuration-hackage2nix.yaml" <> showDefaultWith id <> metavar "PATH")
283−-- <*> option (fmap fromString str) (long "platform" <> help "target platform to generate package set for" <> value "x86_64-linux" <> showDefaultWith display <> metavar "PLATFORM")
284−--
285−-- pinfo :: ParserInfo Options
286−-- pinfo = info
287−-- ( helper
288−-- <*> infoOption ("hackage2nix " ++ display Main.version) (long "version" <> help "Show version number")
289−-- <*> options
290−-- )
291−-- ( fullDesc
292−-- <> header "hackage2nix converts a Hackage database into a hackage-packages.nix file."
293−-- )
294−--
295−-- main :: IO ()
296−-- main = do
297−-- Options {..} <- execParser pinfo
298−--
299−-- -- defaultConfiguration <- readConfiguration configFile
300−-- nixpkgs <- readNixpkgPackageMap "/home/simons/src/cabal2nix/hackage2nix/nixpkgs" Nothing
301−-- -- preferredVersions <- readPreferredVersions (fromMaybe (hackageRepository </> "preferred-versions") preferredVersionsFile)
302−-- let fixup = Map.delete "acme-everything" -- TODO: https://github.com/NixOS/cabal2nix/issues/164
303−-- . Map.delete "som" -- TODO: https://github.com/NixOS/cabal2nix/issues/164
304−-- . Map.delete "type" -- TODO: https://github.com/NixOS/cabal2nix/issues/163
305−-- . Map.delete "dictionary-sharing" -- TODO: https://github.com/NixOS/cabal2nix/issues/175
306−-- -- . Map.filter (/= Map.empty)
307−-- -- . Map.mapWithKey (enforcePreferredVersions preferredVersions)
308−-- hackage <- fixup <$> readHackage hackageRepository
309−-- snapshots <- ParIO.runParIO (readStackage ltsHaskellRepository)
310−--
311−-- let
312−-- allStackagePackages :: Map PackageName (Set Spec)
313−-- allStackagePackages = Map.unionsWith Set.union (map (Map.map Set.singleton . packages) snapshots)
314−--
315−-- notInStackage :: String -> Map Version GenericPackageDescription -> Bool
316−-- notInStackage n _ = isNothing (Map.lookup (PackageName n) allStackagePackages)
317−--
318−-- nonStackagePackages :: Map String Version
319−-- nonStackagePackages = Map.map (Set.findMax . Map.keysSet) (Map.filterWithKey notInStackage hackage)
320−--
321−-- allPackages :: Map PackageName (Set Spec)
322−-- allPackages = Map.union allStackagePackages
323−-- (Map.fromList [ (PackageName n, Set.singleton (Spec v Map.empty True True True)) | (n,v) <- Map.toList nonStackagePackages ])
324−--
325−-- hackagePackagesFile :: FilePath
326−-- hackagePackagesFile = nixpkgsRepository </> "pkgs/development/haskell-modules/hackage-packages.nix"
327−--
328−-- drvs :: Map PackageIdentifier Derivation
329−-- drvs = Map.unions (runPar (parMap (uncurry (formatPackages hackage nixpkgs targetPlatform)) (Map.toList allPackages)))
330−--
331−-- withFile hackagePackagesFile WriteMode $ \h -> do
332−-- hPutStrLn h "{ stdenv }:\n\nself: {"
333−-- forM_ (Map.toList drvs) $ \(pkgId, drv) -> do
334−-- hPutStrLn h $ render $ nest 2 $ hang (doubleQuotes (text (mangle pkgId)) <+> equals) 2 (pPrint drv <> semi)
335−-- hPutChar h '\n'
336−-- hPutStrLn h "}"
337−--
338−-- mapM_ (formatSnapshot drvs nixpkgsRepository) snapshots
339−--
340−-- mangle :: PackageIdentifier -> String
341−-- mangle (PackageIdentifier (PackageName n) v) = n ++ '_' : [ if c == '.' then '_' else c | c <- display v ]
342−--
343−-- formatSnapshot :: Map PackageIdentifier Derivation -> FilePath -> Snapshot -> IO ()
344−-- formatSnapshot drvs nixpkgsRepository (Snapshot {..}) = do
345−-- let
346−-- snapshotId :: String
347−-- snapshotId = show (pPrint snapshot)
348−--
349−-- compilerId :: String
350−-- compilerId = filter (`notElem` ['.','-']) (display compiler)
351−--
352−-- ltsConfigFile :: FilePath
353−-- ltsConfigFile = nixpkgsRepository </> "pkgs/development/haskell-modules/configuration-" ++ snapshotId ++ ".nix"
354−--
355−-- withFile ltsConfigFile WriteMode $ \h -> do
356−-- hPutStrLn h "{ pkgs }:"
357−-- hPutStrLn h ""
358−-- hPutStrLn h "self: super: {"
359−-- hPutStrLn h " # our compiler"
360−-- hPutStrLn h (" ghc = pkgs.haskell.compiler." ++ compilerId ++ ";")
361−-- hPutStrLn h ""
362−-- hPutStrLn h " # core packaged provided by the compiler"
363−-- forM_ (Set.toAscList (Map.keysSet corePackages)) $ \(PackageName n) ->
364−-- unless (n == "ghc") (hPutStrLn h (" " ++ n ++ " = null;"))
365−-- hPutStrLn h ""
366−-- hPutStrLn h " # Stackage"
367−-- forM_ (Map.toAscList packages) $ \(PackageName n, spec) -> do
368−-- let pkgId = PackageIdentifier (PackageName n) (version spec)
369−-- drv = drvs Map.! pkgId
370−-- hPutStrLn h (" \"" ++ n ++ "\" = self.callPackage self.\"" ++ mangle pkgId ++ "\" " ++ render (braces (overrides drv) <> semi))
371−-- hPutStrLn h "}"
372−-- return ()
373−--
374−-- formatPackages :: Hackage -> Map Identifier (Set Path) -> Platform -> PackageName -> Set Spec -> Map PackageIdentifier Derivation
375−-- formatPackages hackage nixpkgs targetPlatform pname specs = Map.fromList
376−-- [ (PackageIdentifier pname (version spec), formatPackage hackage nixpkgs targetPlatform pname spec) | spec <- Set.toList specs ]
377−--
378−-- formatPackage :: Hackage -> Map Identifier (Set Path) -> Platform -> PackageName -> Spec -> Derivation
379−-- formatPackage hackage nixpkgs targetPlatform pname spec =
380−-- let
381−-- pkgId :: PackageIdentifier
382−-- pkgId = PackageIdentifier pname (version spec)
383−--
384−-- abort :: String -> a
385−-- abort msg = error (display pkgId ++ ": " ++ msg)
386−--
387−-- nixpkgsResolver :: Identifier -> Maybe Binding
388−-- nixpkgsResolver = resolve (Map.map (Set.map (over path ("pkgs":))) nixpkgs)
389−--
390−-- pkgDescr :: GenericPackageDescription
391−-- pkgDescr | Just x <- Map.lookup (unPackageName pname) hackage >>= Map.lookup (version spec) = x
392−-- | otherwise = abort "not on hackage"
393−--
394−-- sha256 :: String
395−-- sha256 | Just x <- lookup "X-Package-SHA256" (customFieldsPD (packageDescription pkgDescr)) = x
396−-- | otherwise = abort "cannot find hash"
397−--
398−-- drv :: Derivation
399−-- drv = fromGenericPackageDescription
400−-- (const True)
401−-- nixpkgsResolver
402−-- targetPlatform
403−-- (unknownCompilerInfo (CompilerId GHC (Version [7,10] [])) NoAbiTag)
404−-- (Map.toList (flagOverrides spec))
405−-- []
406−-- pkgDescr
407−-- & src .~ DerivationSource "url" ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") "" sha256
408−-- & doCheck .~ runTests spec
409−-- & Distribution.Nixpkgs.Haskell.runHaddock .~ Stackage.runHaddock spec
410−--
411−-- in drv
412−--
413−--
414−-- -- generatePackageSet :: Platform -> Configuration -> Hackage -> Nixpkgs -> ParIO ()
415−-- -- generatePackageSet targetPlatform config hackage nixpkgs = do
416−-- -- let
417−-- -- corePackageSet :: PackageSet
418−-- -- corePackageSet = Map.fromList [ (name, v) | PackageIdentifier (PackageName name) v <- Set.toList (corePackages config) ]
419−-- --
420−-- -- latestVersionSet :: PackageSet
421−-- -- latestVersionSet = Map.map (Set.findMax . Map.keysSet) hackage
422−-- --
423−-- -- defaultPackageOverridesSet :: PackageSet
424−-- -- defaultPackageOverridesSet = Map.fromList [ (name, resolveConstraint c hackage) | c@(Dependency (PackageName name) _) <- defaultPackageOverrides config ]
425−-- --
426−-- -- generatedDefaultPackageSet :: PackageSet
427−-- -- generatedDefaultPackageSet = (defaultPackageOverridesSet `Map.union` latestVersionSet) `Map.difference` corePackageSet
428−-- --
429−-- -- latestCorePackageSet :: PackageSet
430−-- -- latestCorePackageSet = latestVersionSet `Map.intersection` corePackageSet
431−-- --
432−-- -- latestOverridePackageSet :: PackageSet
433−-- -- latestOverridePackageSet = latestVersionSet `Map.intersection` defaultPackageOverridesSet
434−-- --
435−-- -- extraPackageSet :: PackageMultiSet
436−-- -- extraPackageSet = Map.unionsWith Set.union
437−-- -- [ Map.singleton name (Set.singleton (resolveConstraint c hackage)) | c@(Dependency (PackageName name) _) <- extraPackages config ]
438−-- --
439−-- -- db :: PackageMultiSet
440−-- -- db = Map.unionsWith Set.union [ Map.map Set.singleton generatedDefaultPackageSet
441−-- -- , Map.map Set.singleton latestCorePackageSet
442−-- -- , Map.map Set.singleton latestOverridePackageSet
443−-- -- , extraPackageSet
444−-- -- ]
445−-- --
446−-- -- haskellResolver :: Dependency -> Bool
447−-- -- haskellResolver (Dependency (PackageName name) vrange)
448−-- -- | Just v <- Map.lookup name corePackageSet = v `withinRange` vrange
449−-- -- | Just v <- Map.lookup name generatedDefaultPackageSet = v `withinRange` vrange
450−-- -- | otherwise = False
451−-- --
452−-- -- nixpkgsResolver :: Identifier -> Maybe Binding
453−-- -- nixpkgsResolver = resolve (Map.map (Set.map (over path ("pkgs":))) nixpkgs)
454−-- --
455−-- -- globalPackageMaintainers :: Map PackageName (Set Identifier)
456−-- -- globalPackageMaintainers = Map.unionsWith Set.union [ Map.singleton p (Set.singleton m) | (m,ps) <- Map.toList (packageMaintainers config), p <- Set.toList ps ]
457−-- --
458−-- -- liftIO $ do putStrLn "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"
459−-- -- putStrLn ""
460−-- -- putStrLn "{ pkgs, stdenv, callPackage }:"
461−-- -- putStrLn ""
462−-- -- putStrLn "self: {"
463−-- -- putStrLn ""
464−-- -- pkgs <- flip parMapM (Map.toAscList db) $ \(name, vs) -> do
465−-- -- defs <- forM (Set.toAscList vs) $ \pkgversion -> do
466−-- -- let -- TODO: Include list of broken dependencies in the generated output.
467−-- -- descr = hackage Map.! name Map.! pkgversion
468−-- --
469−-- -- flagAssignment :: FlagAssignment
470−-- -- flagAssignment = configureCabalFlags (packageId descr)
471−-- --
472−-- -- drv' :: Derivation
473−-- -- drv' = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr
474−-- --
475−-- -- isInDefaultPackageSet :: Bool
476−-- -- isInDefaultPackageSet = maybe False (== pkgversion) (Map.lookup name generatedDefaultPackageSet)
477−-- --
478−-- -- attr :: String
479−-- -- attr = name ++ if isInDefaultPackageSet then [] else '_' : [ if c == '.' then '_' else c | c <- display pkgversion ]
480−-- --
481−-- -- sha256 :: String
482−-- -- sha256 | Just x <- lookup "X-Package-SHA256" (customFieldsPD (packageDescription descr)) = x
483−-- -- | otherwise = error $ display (packageId descr) ++ " has no hash"
484−-- --
485−-- -- srcSpec <- liftIO $ sourceFromHackage (Certain sha256) (name ++ "-" ++ display pkgversion)
486−-- --
487−-- -- let drv = drv' & src .~ srcSpec
488−-- -- & metaSection.hydraPlatforms %~ (`Set.difference` fromMaybe Set.empty (Map.lookup (PackageName name) (dontDistributePackages config)))
489−-- -- & metaSection.hydraPlatforms %~ (if isInDefaultPackageSet then id else const Set.empty)
490−-- -- & metaSection.maintainers .~ fromMaybe Set.empty (Map.lookup (PackageName name) globalPackageMaintainers)
491−-- --
492−-- -- isFromHackage :: Binding -> Bool
493−-- -- isFromHackage b = case view (reference . path) b of
494−-- -- ["self",_] -> True
495−-- -- _ -> False
496−-- --
497−-- -- overrides :: Doc
498−-- -- overrides = fcat $ punctuate space
499−-- -- [ pPrint b | b <- Set.toList (view (dependencies . each) drv), not (isFromHackage b) ]
500−-- --
501−-- -- return $ nest 2 $ hang (doubleQuotes (text attr) <+> equals <+> text "callPackage") 2 (parens (pPrint drv)) <+> (braces overrides <> semi)
502−-- -- return (intercalate "\n\n" (map render defs))
503−-- --
504−-- -- liftIO $ mapM_ (\pkg -> putStrLn pkg >> putStrLn "") pkgs
505−-- -- liftIO $ putStrLn "}"
506−--
507−-- -- readPreferredVersions :: FilePath -> IO [Constraint]
508−-- -- readPreferredVersions p = mapMaybe parsePreferredVersionsLine . lines <$> readFile p
509−--
510−-- -- parsePreferredVersionsLine :: String -> Maybe Constraint
511−-- -- parsePreferredVersionsLine [] = Nothing
512−-- -- parsePreferredVersionsLine ('-':'-':_) = Nothing
513−-- -- parsePreferredVersionsLine l = simpleParse l `mplus` error ("invalid preferred-versions line: " ++ show l)
514−--
515−-- -- enforcePreferredVersions :: [Constraint] -> String -> Map Version GenericPackageDescription
516−-- -- -> Map Version GenericPackageDescription
517−-- -- enforcePreferredVersions cs pkg = Map.filterWithKey (\v _ -> PackageIdentifier (PackageName pkg) v `satisfiesConstraints` cs)
518−--
519−-- overrides :: Derivation -> Doc
520−-- overrides drv = fcat $ punctuate space [ pPrint b | b <- Set.toList (view (dependencies . each) drv), not (isFromHackage b) ]
521−--
522−-- isFromHackage :: Binding -> Bool
523−-- isFromHackage b = case view (reference . path) b of
524−-- ["self",_] -> True
525−-- _ -> False
203+enforcePreferredVersions :: [Constraint] -> String -> Map Version GenericPackageDescription
204+ -> Map Version GenericPackageDescription
205+enforcePreferredVersions cs pkg = Map.filterWithKey (\v _ -> PackageIdentifier (PackageName pkg) v `satisfiesConstraints` cs)
hackage2nix/src/Stackage.hs+47−25
@@ -9,9 +9,13 @@ import Control.Monad
99import Control.Monad.Par.Combinator
1010import Control.Monad.Par.IO
1111import Control.Monad.Trans
12+import Data.List
13+import Data.List.Split
1214import Data.Map as Map
1315import Data.Maybe
14−import Data.Yaml ( decodeFile )
16+import Data.Time.Calendar
17+import Data.Yaml
18+import Distribution.Compiler
1519import Distribution.Nixpkgs.Haskell.OrphanInstances ( )
1620import Distribution.Package
1721import Distribution.PackageDescription
@@ -20,58 +24,76 @@ import GHC.Generics ( Generic )
2024import Stackage.Types hiding ( display )
2125import System.Directory
2226import System.FilePath
23−import Text.Show.Pretty
24−import Distribution.Compiler
25−
26−yo :: IO ()
27−yo = readView "/home/simons/src/cabal2nix/hackage2nix/stackage-nightly/nightly-2015-09-11.yaml" >>= putStrLn . ppShow
27+import Text.PrettyPrint.HughesPJClass
2828
2929data Spec = Spec
3030 { version :: Version
31− , flagOverrides :: (Map FlagName Bool)
31+ , flagOverrides :: Map FlagName Bool
3232 , runTests :: Bool
3333 , runHaddock :: Bool
3434 , runLinuxBuilds :: Bool
3535 }
36− deriving (Show, Eq, Ord, Generic)
36+ deriving (Show, Generic)
3737
38−data View = View
39− { compiler :: CompilerId
38+instance Eq Spec where
39+ a == b = version a == version b
40+
41+instance Ord Spec where
42+ compare a b = compare (version a) (version b)
43+
44+data Snapshot = Snapshot
45+ { snapshot :: SnapshotType
46+ , compiler :: CompilerId
4047 , corePackages :: Map PackageName Version
4148 , packages :: Map PackageName Spec
4249 }
4350 deriving (Show, Generic)
4451
52+deriving instance Generic SnapshotType
4553instance NFData Spec where
46−instance NFData View where
54+instance NFData Snapshot where
55+instance NFData SnapshotType where
4756
48−views :: IO [View]
49−views = runParIO $ readStackage "lts-haskell"
57+instance Pretty SnapshotType where
58+ pPrint STNightly = text "stackage-nightly"
59+ pPrint (STNightly2 _) = text "stackage-nightly"
60+ pPrint (STLTS m n) = text "lts-" <> int m <> char '.' <> int n
5061
51−readStackage :: FilePath -> ParIO [View]
62+readStackage :: FilePath -> ParIO [Snapshot]
5263readStackage dirPath = do
5364 filePaths <- liftIO (listFiles dirPath)
54− parMapM (liftIO . readView) [ dirPath </> p | p <- filePaths, takeExtension p == ".yaml" ]
65+ parMapM (liftIO . readSnapshot) [ dirPath </> p | p <- filePaths, takeExtension p == ".yaml" ]
5566
56−readView :: FilePath -> IO View
57−readView = fmap fromBuildPlan . readBuildPlan
67+readSnapshot :: FilePath -> IO Snapshot
68+readSnapshot p = fmap (fromBuildPlan (parseSnapshotType (takeFileName p))) (readBuildPlan p)
5869
59−fromBuildPlan :: BuildPlan -> View
60−fromBuildPlan bp = View (CompilerId GHC (siGhcVersion (bpSystemInfo bp)))
61− (siCorePackages (bpSystemInfo bp))
62− (Map.map fromPackagePlan (bpPackages bp))
70+parseSnapshotType :: FilePath -> SnapshotType
71+parseSnapshotType p
72+ | "lts-" `isPrefixOf` p
73+ , [major,minor] <- splitOn "." (drop 4 (dropExtension p))
74+ = STLTS (read major) (read minor)
75+ | "nightly-" `isPrefixOf` p
76+ , [year,month,day] <- splitOn "-" (drop 8 (dropExtension p))
77+ = STNightly2 (fromGregorian (read year) (read month) (read day))
78+ | otherwise = error ("parseSnapshotType: invalid file name " ++ p)
79+
80+readBuildPlan :: FilePath -> IO BuildPlan
81+readBuildPlan = fmap fromJust . decodeFile
82+
83+fromBuildPlan :: SnapshotType -> BuildPlan -> Snapshot
84+fromBuildPlan snt bp = Snapshot snt
85+ (CompilerId GHC (siGhcVersion (bpSystemInfo bp)))
86+ (siCorePackages (bpSystemInfo bp))
87+ (Map.map fromPackagePlan (bpPackages bp))
6388
6489fromPackagePlan :: PackagePlan -> Spec
6590fromPackagePlan pp = Spec (ppVersion pp)
6691 (pcFlagOverrides ppc)
6792 (pcTests ppc == ExpectSuccess)
6893 (pcHaddocks ppc == ExpectSuccess)
69− (pcSkipBuild ppc)
94+ (not (pcSkipBuild ppc))
7095 where ppc = ppConstraints pp
7196
72−readBuildPlan :: FilePath -> IO BuildPlan
73−readBuildPlan = fmap fromJust . decodeFile
74−
7597listFiles :: FilePath -> IO [FilePath]
7698listFiles path = do
7799 let isFile p = doesFileExist (path </> p)