git.iko.soy/typeable/cabal2nix
on master help sign in
hackage2nix.hs: implement more sophisticated package set building logic
d64370fPeter Simons
src/hackage2nix.hs+48−24
@@ -39,7 +39,22 @@ main = do
39
39
40generatePackageSet :: Hackage -> PackageMap -> ParIO ()
40generatePackageSet :: Hackage -> PackageMap -> ParIO ()
41generatePackageSet hackage nixpkgs = do
41generatePackageSet hackage nixpkgs = do
42− let db = buildPackageSet hackage
42+ let defaultPackageSet = buildDefaultPackageSet hackage defaultPackageOverrides
43+ extendedPackageSet = buildExtendedPackageSet hackage extraPackages
44+ db = defaultPackageSet `mergePackageSet` extendedPackageSet
45+
46+ matches :: PackageIdentifier -> Dependency -> Bool
47+ matches (PackageIdentifier pn v) (Dependency dn vr) = pn == dn && v `withinRange` vr
48+
49+ resolver :: Dependency -> Bool
50+ resolver dep@(Dependency (PackageName pkg) vrange) =
51+ any (`matches` dep) corePackages ||
52+ maybe False (not . Map.null . Map.filterWithKey (\k _ -> k `withinRange` vrange)) (Map.lookup pkg defaultPackageSet)
53+
54+ forM_ (Map.assocs defaultPackageSet) $ \(name, vdb) ->
55+ when (Map.size vdb /= 1) $
56+ fail ("invalid defaut package set: " ++ show (name, Map.keys vdb))
57+
43 liftIO $ do putStrLn "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"
58 liftIO $ do putStrLn "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"
44 putStrLn ""
59 putStrLn ""
45 putStrLn "{ pkgs, stdenv, callPackage }:"
60 putStrLn "{ pkgs, stdenv, callPackage }:"
@@ -50,16 +65,16 @@ generatePackageSet hackage nixpkgs = do
50 let multiVersionPackage :: Bool
65 let multiVersionPackage :: Bool
51 multiVersionPackage = Map.size versions > 1
66 multiVersionPackage = Map.size versions > 1
52
67
53− latestVersion :: Version
68+ defaultVersion :: Version
54− latestVersion = fst (Map.findMax versions)
69+ defaultVersion = fst $ Map.findMax $ (Map.!) defaultPackageSet name
55
70
56 pkg <- forM (Map.toList versions) $ \(version, descr) -> do
71 pkg <- forM (Map.toList versions) $ \(version, descr) -> do
57− (drv, overrides) <- generatePackage db nixpkgs name version descr
72+ (drv, overrides) <- generatePackage db resolver nixpkgs name version descr
58
73
59 let nixAttr = name ++ if multiVersionPackage then "_" ++ [ if c == '.' then '_' else c | c <- display version ] else ""
74 let nixAttr = name ++ if multiVersionPackage then "_" ++ [ if c == '.' then '_' else c | c <- display version ] else ""
60
75
61 let def = nest 2 $ hang ((string nixAttr) <+> equals <+> text "callPackage") 2 (parens (disp drv)) <+> (braces overrides <> semi)
76 let def = nest 2 $ hang ((string nixAttr) <+> equals <+> text "callPackage") 2 (parens (disp drv)) <+> (braces overrides <> semi)
62− let overr = if multiVersionPackage && version == latestVersion
77+ let overr = if multiVersionPackage && version == defaultVersion
63 then nest 2 $ (string name <+> equals <+> text ("self." ++ show nixAttr)) <> semi
78 then nest 2 $ (string name <+> equals <+> text ("self." ++ show nixAttr)) <> semi
64 else empty
79 else empty
65
80
@@ -70,19 +85,11 @@ generatePackageSet hackage nixpkgs = do
70 liftIO $ mapM_ putStrLn pkgs
85 liftIO $ mapM_ putStrLn pkgs
71 liftIO $ putStrLn "}"
86 liftIO $ putStrLn "}"
72
87
73−generatePackage :: Hackage -> PackageMap -> String -> Version -> GenericPackageDescription -> ParIO (Derivation, Doc)
88+generatePackage :: Hackage -> (Dependency -> Bool) -> PackageMap -> String -> Version -> GenericPackageDescription -> ParIO (Derivation, Doc)
74−generatePackage hackage nixpkgs name version descr = do
89+generatePackage hackage resolver nixpkgs name version descr = do
75 srcSpec <- liftIO $ sourceFromHackage Nothing (name ++ "-" ++ display version)
90 srcSpec <- liftIO $ sourceFromHackage Nothing (name ++ "-" ++ display version)
76 let Just cabalFileHash = lookup "x-cabal-file-hash" (customFieldsPD (packageDescription descr))
91 let Just cabalFileHash = lookup "x-cabal-file-hash" (customFieldsPD (packageDescription descr))
77
92
78− matches :: PackageIdentifier -> Dependency -> Bool
79− matches (PackageIdentifier pn v) (Dependency dn vr) = pn == dn && v `withinRange` vr
80−
81− resolver :: Dependency -> Bool
82− resolver dep@(Dependency (PackageName pkg) vrange) =
83− any (`matches` dep) corePackages ||
84− maybe False (not . Map.null . Map.filterWithKey (\k _ -> k `withinRange` vrange)) (Map.lookup pkg hackage)
85−
86 -- TODO: Include list of broken dependencies in the generated output.
93 -- TODO: Include list of broken dependencies in the generated output.
87 (missingDeps,drv') <- case cabal2nix resolver descr of
94 (missingDeps,drv') <- case cabal2nix resolver descr of
88 Left ds -> do let Right x = cabal2nix (const True) descr
95 Left ds -> do let Right x = cabal2nix (const True) descr
@@ -128,10 +135,32 @@ isKnownNixpkgAttribute nixpkgs hackage name
128 goodScope :: Set [String] -> Bool
135 goodScope :: Set [String] -> Bool
129 goodScope = not . Set.null . Set.intersection (Set.fromList [[], ["xlibs"], ["gnome"]])
136 goodScope = not . Set.null . Set.intersection (Set.fromList [[], ["xlibs"], ["gnome"]])
130
137
131−buildPackageSet :: Hackage -> Hackage
138+buildDefaultPackageSet :: Hackage -> [Dependency] -> Hackage
132−buildPackageSet db = Map.unionsWith Map.union $
139+buildDefaultPackageSet hackage overrides = Map.unions $ -- unions is left-biased, i.e. overrides trump the latest version
140+ [ selectLatestMatchingPackage p hackage | p <- overrides ] ++
133− [ selectLatestMatchingPackage (Dependency (PackageName n) anyVersion) db | n <- Map.keys db ] ++
141+ [ selectLatestMatchingPackage (Dependency (PackageName n) anyVersion) hackage | n <- Map.keys hackage ]
142+
143+buildExtendedPackageSet :: Hackage -> [Dependency] -> Hackage
144+buildExtendedPackageSet hackage extras = Map.unionsWith Map.union
134− [ selectLatestMatchingPackage d db | d <- selectors ]
145+ [ selectLatestMatchingPackage p hackage | p <- extras ]
146+
147+mergePackageSet :: Hackage -> Hackage -> Hackage
148+mergePackageSet = Map.unionWith Map.union
149+
150+-- These packages replace the latest respective version during dependency resolution.
151+defaultPackageOverrides :: [Dependency]
152+defaultPackageOverrides = map (\s -> maybe (error (show s ++ " is not a valid override selector")) id (simpleParse s))
153+ [ "mtl == 2.1.*"
154+ , "monad-control == 0.3.*"
155+ ]
156+
157+-- These packages are added to the generated set, but the play no role during dependency resolution.
158+extraPackages :: [Dependency]
159+extraPackages =
160+ map (\(Dependency name _) -> Dependency name anyVersion) defaultPackageOverrides ++
161+ map (\s -> maybe (error (show s ++ " is not a valid extra package selector")) id (simpleParse s))
162+ [
163+ ]
135
164
136selectLatestMatchingPackage :: Dependency -> Hackage -> Hackage
165selectLatestMatchingPackage :: Dependency -> Hackage -> Hackage
137selectLatestMatchingPackage (Dependency (PackageName name) vrange) db =
166selectLatestMatchingPackage (Dependency (PackageName name) vrange) db =
@@ -140,11 +169,6 @@ selectLatestMatchingPackage (Dependency (PackageName name) vrange) db =
140 Just vdb -> let (key,val) = Map.findMax (Map.filterWithKey (\k _ -> k `withinRange` vrange) vdb)
169 Just vdb -> let (key,val) = Map.findMax (Map.filterWithKey (\k _ -> k `withinRange` vrange) vdb)
141 in Map.singleton name (Map.singleton key val)
170 in Map.singleton name (Map.singleton key val)
142
171
143−selectors :: [Dependency]
144−selectors = map (\s -> maybe (error (show s ++ " is not a valid package selector")) id (simpleParse s))
145− [ "mtl == 2.1.*"
146− , "monad-control == 0.3.*"
147− ]
148
172
149-- data Options = Options
173-- data Options = Options
150-- { verbose :: Bool
174-- { verbose :: Bool