@@ -1,167 +0,0 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE PartialTypeSignatures #-}
3−{-# LANGUAGE ScopedTypeVariables #-}
4−
5−module Stackage2nix where
6−
7−import AllCabalHashes
8−import Data.Monoid
9−import Options.Applicative
10−import Stackage.BuildPlan
11−import Stackage.Types (SystemInfo(..))
12−import Paths_stack2nix as Main
13−import Distribution.Text (display)
14−import Control.Monad
15−import Text.PrettyPrint.HughesPJClass hiding ((<>))
16−import Distribution.Compiler (CompilerInfo(..), AbiTag(NoAbiTag), CompilerId(..), CompilerFlavor(GHC))
17−import Distribution.System (Platform(..))
18−import Distribution.Package (PackageName, PackageIdentifier(..), Dependency(..))
19−import Distribution.Nixpkgs.Haskell.PackageSourceSpec
20−import Distribution.Nixpkgs.Haskell.FromStack
21−import Distribution.Nixpkgs.Haskell.FromStack.Package
22−import Distribution.Nixpkgs.Fetch
23−import Distribution.Nixpkgs.PackageMap (readNixpkgPackageMap, resolve, PackageMap)
24−import Distribution.Version (Version, withinRange)
25−import Language.Haskell.Extension (Language(Haskell98, Haskell2010))
26−import Language.Nix
27−import Control.Lens
28−import Data.Maybe
29−import System.IO (withFile, IOMode(..), hPutStrLn)
30−
31−import qualified Data.Aeson as Aeson
32−import qualified Data.Yaml as Yaml
33−import qualified Data.Map as Map
34−import qualified Data.Set as Set
35−import qualified Data.ByteString as ByteString
36−import qualified Data.Text as Text
37−import qualified Data.HashMap.Strict as HashMap
38−
39−
40−data Options = Options
41− { optBuildPlanFile :: FilePath
42− , optAllCabalHashes :: FilePath
43− , optDoCheck :: Bool
44− , optDoHaddock :: Bool
45− , optNixpkgsRepository :: FilePath
46− , optNixpkgsMap :: Maybe FilePath
47− , optOutPackages :: FilePath
48− , optOutConfig :: FilePath
49− }
50−
51−options :: Parser Options
52−options = Options
53− <$> strArgument (metavar "PLAN" <> help "stackage build plan (YAML)")
54− <*> strArgument (metavar "CABALFILES" <> help "path to checkout of all-cabal-hashes")
55− <*> switch (long "do-check" <> help "enable tests for Stackage packages")
56− <*> switch (long "do-haddock" <> help "enable haddock for Stackage packages")
57− <*> strOption (long "nixpkgs" <> help "path to Nixpkgs repository" <> value "<nixpkgs>" <> showDefaultWith id <> metavar "PATH")
58− <*> optional (strOption (long "package-map" <> help "path to a serialized nixpkgs package map" <> metavar "PATH"))
59− <*> strOption (long "out-packages" <> help "name of the output file for the package set" <> value "packages.nix" <> metavar "PATH")
60− <*> strOption (long "out-config" <> help "name of the output file for the package set configuration" <> value "configuration-packages.nix" <> metavar "PATH")
61−
62−pinfo :: ParserInfo Options
63−pinfo = info
64− ( helper
65− <*> infoOption ("stackage2nix " ++ display Main.version) (long "version" <> help "Show version number")
66− <*> options
67− )
68− ( fullDesc
69− <> header "stackage2nix converts stackage snapshots into a nix package set"
70− )
71−
72−loadBuildPlan :: FilePath -> IO BuildPlan
73−loadBuildPlan = Yaml.decodeFileEither >=> \case
74− Left err -> fail $ "Failed to parse stackage build plan: " ++ show err
75− Right bp -> return bp
76−
77−loadPackage :: FilePath -> Maybe SHA1Hash -> PackageIdentifier -> IO Package
78−loadPackage allCabalHashesPath mSha1Hash pkgId = do
79− (pkgDesc, _) <- case mSha1Hash of
80− Just sha1 -> readPackageByHash allCabalHashesPath sha1
81− Nothing -> readPackageByName allCabalHashesPath pkgId
82− meta <- readPackageMeta allCabalHashesPath pkgId
83− let
84− tarballSHA256 = fromMaybe
85− (error (display pkgId ++ ": meta data has no SHA256 hash for the tarball"))
86− (view (mHashes . at "SHA256") meta)
87− source = DerivationSource "url" ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") "" tarballSHA256
88− return $ Package source pkgDesc
89−
90−ghcCompilerInfo :: Version -> CompilerInfo
91−ghcCompilerInfo v = CompilerInfo
92− { compilerInfoId = CompilerId GHC v
93− , compilerInfoAbiTag = NoAbiTag
94− , compilerInfoCompat = Just []
95− , compilerInfoLanguages = Just [Haskell98, Haskell2010]
96− , compilerInfoExtensions = Nothing
97− }
98−
99−buildPlanContainsDependency :: Map.Map PackageName Version -> Dependency -> Bool
100−buildPlanContainsDependency packageVersions (Dependency depName versionRange) =
101− maybe False (`withinRange` versionRange) $ Map.lookup depName packageVersions
102−
103−newtype SerializablePackageMap = SerializablePackageMap { getPackageMap :: PackageMap }
104−
105−instance Aeson.ToJSON SerializablePackageMap where
106− toJSON (SerializablePackageMap m) = Aeson.object . map makeEntry $ Map.toList m
107− where
108− makeEntry (i, s) = (Text.pack (view ident i), Aeson.toJSON . map makePath $ Set.toList s)
109− makePath = view (path . mapping ident)
110−
111−instance Aeson.FromJSON SerializablePackageMap where
112− parseJSON = Aeson.withObject "package map object" $
113− fmap (SerializablePackageMap . Map.fromList) . traverse makeEntry . HashMap.toList
114− where
115− makeEntry (i, s) = Aeson.parseJSON s <&> \s' -> (ident # Text.unpack i, Set.fromList (map makePath s'))
116− makePath = review (path . mapping ident)
117−
118−run :: Options -> IO (BuildPlan, PackageSetConfig)
119−run Options{..} = do
120− nixpkgs <- fromMaybe (readNixpkgPackageMap optNixpkgsRepository Nothing) $ do
121− mapFile <- optNixpkgsMap
122− return $ do
123− contents <- ByteString.readFile mapFile
124− case Aeson.eitherDecodeStrict contents of
125− Left err -> fail $ "Failed to decode package map " ++ show mapFile ++ ": " ++ err
126− Right v -> return $ getPackageMap v
127−
128− buildPlan <- loadBuildPlan optBuildPlanFile
129−
130− let
131− systemInfo = bpSystemInfo buildPlan
132− packageVersions = fmap ppVersion (bpPackages buildPlan) `Map.union` siCorePackages systemInfo
133− conf = PackageSetConfig
134− { packageLoader = loadPackage optAllCabalHashes
135− , targetPlatform = Platform (siArch systemInfo) (siOS systemInfo)
136− , targetCompiler = ghcCompilerInfo (siGhcVersion systemInfo)
137− , nixpkgsResolver = resolve (Map.map (Set.map (over path ("pkgs":))) nixpkgs)
138− , haskellResolver = buildPlanContainsDependency packageVersions
139− , enableCheck = optDoCheck
140− , enableHaddock = optDoHaddock
141− }
142− return (buildPlan, conf)
143−
144−writeOutPackages :: FilePath -> FilePath -> [Node] -> IO ()
145−writeOutPackages optBuildPlanFile optOutPackages nodes =
146− withFile optOutPackages WriteMode $ \h -> do
147− hPutStrLn h ("# Generated by stackage2nix from " ++ optBuildPlanFile)
148− hPutStrLn h $ render $ pPrintOutPackages (view nodeDerivation <$> nodes)
149−
150−writeOutConfig :: FilePath -> FilePath -> SystemInfo -> [Node] -> IO ()
151−writeOutConfig optBuildPlanFile optOutConfig systemInfo nodes =
152− withFile optOutConfig WriteMode $ \h -> do
153− hPutStrLn h ("# Generated by stackage2nix from " ++ optBuildPlanFile)
154− hPutStrLn h $ render $ pPrintOutConfig systemInfo nodes
155−
156−main :: IO ()
157−main = do
158− opts@Options{..} <- execParser pinfo
159− (buildPlan, conf) <- run opts
160− let systemInfo = bpSystemInfo buildPlan
161− nodes <- traverse (uncurry $ buildNodeM conf) $ Map.toList (bpPackages buildPlan)
162− withFile optOutPackages WriteMode $ \h -> do
163− hPutStrLn h ("# Generated by stackage2nix from " ++ optBuildPlanFile)
164− hPutStrLn h $ render $ pPrintOutPackages (view nodeDerivation <$> nodes)
165− withFile optOutConfig WriteMode $ \h -> do
166− hPutStrLn h ("# Generated by stackage2nix from " ++ optBuildPlanFile)
167− hPutStrLn h $ render $ pPrintOutConfig systemInfo nodes