@@ -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-- 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)
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"
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
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
63 deriving (Show)
54 deriving (Show)
65−options :: Parser 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")
75−pinfo :: ParserInfo Options
78− <*> infoOption ("hackage2nix " ++ display Config.version) (long "version" <> help "Show version number")
82− <> header "hackage2nix converts a Hackage database into a haskell-packages.nix file."
85main :: IO ()
56main :: IO ()
58+ let cliOptions :: Parser 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")
68+ pinfo :: ParserInfo CLI
71+ <*> infoOption ("hackage2nix " ++ display Config.version) (long "version" <> help "Show version number")
75+ <> header "hackage2nix converts a Hackage database into a hackage-packages.nix file."
87− Options {..} <- execParser pinfo
77+ CLI {..} <- execParser pinfo
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)
89+ hackagePackagesFile :: FilePath
90+ hackagePackagesFile = nixpkgsRepository </> "pkgs/development/haskell-modules/hackage-packages.nix"
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) ]
@@ -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 ]
144− do putStrLn "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"
146− putStrLn "{ pkgs, stdenv, callPackage }:"
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 ->
@@ -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)))
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
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)
174+ withFile hackagePackagesFile WriteMode $ \h -> do
175+ hPutStrLn h "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"
177+ hPutStrLn h "{ pkgs, stdenv, callPackage }:"
179+ hPutStrLn h "self: {"
187− mapM_ (\pkg -> putStrLn pkg >> putStrLn "") pkgs
181+ mapM_ (\pkg -> hPutStrLn h pkg >> hPutStrLn h "") pkgs
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 }:"
191+ hPutStrLn h ("self: super: assert super.ghc.name == " ++ show (display compiler) ++ "; {")
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;"))
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))) ++ ";")
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)
224+resolveConstraint :: Constraint -> Hackage -> Version
225+resolveConstraint c = fromMaybe (error msg) . resolveConstraint' c
226+ where msg = "constraint " ++ display c ++ " cannot be resolved in Hackage"
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
235+mangle :: PackageIdentifier -> String
236+mangle (PackageIdentifier (PackageName name) v) = name ++ '_' : [ if c == '.' then '_' else c | c <- display v ]