Minor revision
authorAndrey Mokhov <andrey.mokhov@gmail.com>
Fri, 18 Aug 2017 23:31:39 +0000 (00:31 +0100)
committerAndrey Mokhov <andrey.mokhov@gmail.com>
Fri, 18 Aug 2017 23:31:39 +0000 (00:31 +0100)
src/GHC.hs
src/Hadrian/Haskell/Cabal.hs
src/Hadrian/Haskell/Package.hs
src/Settings.hs
src/Settings/Builders/GhcCabal.hs
src/Settings/Packages/GhcCabal.hs
src/Utilities.hs

index 2a641e5..2c6dff3 100644 (file)
@@ -99,19 +99,19 @@ win32               = lib  "Win32"
 xhtml               = lib  "xhtml"
 
 -- | Construct a library package, e.g. @array@.
-lib :: String -> Package
+lib :: PackageName -> Package
 lib name = library name ("libraries" -/- name)
 
 -- | Construct a top-level library package, e.g. @compiler@.
-top :: String -> Package
+top :: PackageName -> Package
 top name = library name name
 
 -- | Construct a top-level program package, e.g. @ghc@.
-prg :: String -> Package
+prg :: PackageName -> Package
 prg name = program name name
 
 -- | Construct a utility package, e.g. @haddock@.
-util :: String -> Package
+util :: PackageName -> Package
 util name = program name ("utils" -/- name)
 
 -- | Amend a package path if it doesn't conform to a typical pattern.
index d579de6..075cd77 100644 (file)
@@ -9,41 +9,44 @@
 -- Basic functionality for extracting Haskell package metadata stored in
 -- @.cabal@ files.
 -----------------------------------------------------------------------------
-module Hadrian.Haskell.Cabal (readCabal, cabalNameVersion, cabalDependencies) where
+module Hadrian.Haskell.Cabal (readCabal, pkgNameVersion, pkgDependencies) where
 
 import Development.Shake
-import Distribution.Package
-import Distribution.PackageDescription
-import Distribution.PackageDescription.Parse
-import Distribution.Text
-import Distribution.Types.CondTree
-import Distribution.Verbosity
+import qualified Distribution.Package                  as C
+import qualified Distribution.PackageDescription       as C
+import qualified Distribution.PackageDescription.Parse as C
+import qualified Distribution.Text                     as C
+import qualified Distribution.Types.CondTree           as C
+import qualified Distribution.Verbosity                as C
 
--- | Read a given @.cabal@ file and return the 'GenericPackageDescription'. The
--- @.cabal@ file is tracked.
-readCabal :: FilePath -> Action GenericPackageDescription
-readCabal cabal = do
-    need [cabal]
-    liftIO $ readGenericPackageDescription silent cabal
+import Hadrian.Haskell.Package
 
--- | Read a given @.cabal@ file and return the package name and version. The
--- @.cabal@ file is tracked.
-cabalNameVersion :: FilePath -> Action (String, String)
-cabalNameVersion cabal = do
-    identifier <- package . packageDescription <$> readCabal cabal
-    return (unPackageName $ pkgName identifier, display $ pkgVersion identifier)
+-- | Read the @.cabal@ file of a given package and return the
+-- 'GenericPackageDescription'. The @.cabal@ file is tracked.
+readCabal :: Package -> Action C.GenericPackageDescription
+readCabal pkg = do
+    need [pkgCabalFile pkg]
+    liftIO $ C.readGenericPackageDescription C.silent (pkgCabalFile pkg)
 
--- | Read a given @.cabal@ file and return the package dependencies. The
--- @.cabal@ file is tracked.
-cabalDependencies :: FilePath -> Action [String]
-cabalDependencies cabal = do
-    gpd <- readCabal cabal
-    let libDeps = collectDeps (condLibrary gpd)
-        exeDeps = map (collectDeps . Just . snd) (condExecutables gpd)
-    return [ unPackageName p | Dependency p _ <- concat (libDeps : exeDeps) ]
+-- | Read the @.cabal@ file of a given package and return the package name and
+-- version. The @.cabal@ file is tracked.
+pkgNameVersion :: Package -> Action (PackageName, String)
+pkgNameVersion pkg = do
+    pkgId <- C.package . C.packageDescription <$> readCabal pkg
+    return (C.unPackageName $ C.pkgName pkgId, C.display $ C.pkgVersion pkgId)
 
-collectDeps :: Maybe (CondTree v [Dependency] a) -> [Dependency]
+-- | Read the @.cabal@ file of a given package and return the list of its
+-- dependencies. The current version does not take care of Cabal conditionals
+-- and therefore returns a crude overapproximation of The @.cabal@ file is tracked.
+pkgDependencies :: Package -> Action [PackageName]
+pkgDependencies pkg = do
+    gpd <- readCabal pkg
+    let libDeps = collectDeps (C.condLibrary gpd)
+        exeDeps = map (collectDeps . Just . snd) (C.condExecutables gpd)
+    return [ C.unPackageName p | C.Dependency p _ <- concat (libDeps : exeDeps) ]
+
+collectDeps :: Maybe (C.CondTree v [C.Dependency] a) -> [C.Dependency]
 collectDeps Nothing = []
-collectDeps (Just (CondNode _ deps ifs)) = deps ++ concatMap f ifs
+collectDeps (Just (C.CondNode _ deps ifs)) = deps ++ concatMap f ifs
   where
-    f (CondBranch _ t mt) = collectDeps (Just t) ++ collectDeps mt
+    f (C.CondBranch _ t mt) = collectDeps (Just t) ++ collectDeps mt
index 97a4ae3..bcba5cf 100644 (file)
@@ -10,7 +10,7 @@
 -----------------------------------------------------------------------------
 module Hadrian.Haskell.Package (
     -- * Data type
-    Package,
+    Package, PackageName,
 
     -- * Construction and properties
     library, program, pkgName, pkgPath, isLibrary, isProgram,
@@ -24,6 +24,8 @@ import Development.Shake.FilePath
 import GHC.Generics
 import Hadrian.Utilities
 
+type PackageName = String
+
 -- TODO: Make PackageType more precise, #12.
 data PackageType = Library | Program deriving (Generic, Show)
 
@@ -32,10 +34,10 @@ data PackageType = Library | Program deriving (Generic, Show)
 -- packages can be both. This works for now, but in future we plan to support
 -- general Haskell packages. Also note that we assume that all packages have
 -- different names, hence two packages with the same name are considered equal.
-data Package = Package PackageType String FilePath deriving Generic
+data Package = Package PackageType PackageName FilePath deriving Generic
 
 -- | The name of a Haskell package. Examples: @Cabal@, @ghc-bin@.
-pkgName :: Package -> String
+pkgName :: Package -> PackageName
 pkgName (Package _ name _) = name
 
 -- | The path to the package source code relative to the root of the build
@@ -63,17 +65,13 @@ instance Hashable PackageType
 instance NFData   PackageType
 
 -- | Construct a library package.
-library :: String -> FilePath -> Package
+library :: PackageName -> FilePath -> Package
 library = Package Library
 
 -- | Construct a program package.
-program :: String -> FilePath -> Package
+program :: PackageName -> FilePath -> Package
 program = Package Program
 
--- | The path to a package cabal file, e.g.: @ghc/ghc-bin.cabal@.
-pkgCabalFile :: Package -> FilePath
-pkgCabalFile pkg = pkgPath pkg -/- pkgName pkg <.> "cabal"
-
 -- | Check whether a package is a library.
 isLibrary :: Package -> Bool
 isLibrary (Package Library _ _) = True
@@ -83,3 +81,7 @@ isLibrary _ = False
 isProgram :: Package -> Bool
 isProgram (Package Program _ _) = True
 isProgram _ = False
+
+-- | The path to a package cabal file, e.g.: @ghc/ghc-bin.cabal@.
+pkgCabalFile :: Package -> FilePath
+pkgCabalFile pkg = pkgPath pkg -/- pkgName pkg <.> "cabal"
index 5e4ded9..9fafd1e 100644 (file)
@@ -62,7 +62,7 @@ knownPackages = sort $ defaultKnownPackages ++ userKnownPackages
 
 -- TODO: Speed up? Switch to Set?
 -- Note: this is slow but we keep it simple as there are just ~50 packages
-findKnownPackage :: String -> Maybe Package
+findKnownPackage :: PackageName -> Maybe Package
 findKnownPackage name = find (\pkg -> pkgName pkg == name) knownPackages
 
 -- | Determine the location of a 'Builder'.
index d6c1c74..285a3d5 100644 (file)
@@ -96,7 +96,7 @@ bootPackageConstraintsGenerator _ = do
     bootPkgs <- stagePackages Stage0
     let pkgs = filter (\p -> p /= compiler && isLibrary p) bootPkgs
     constraints <- forM (sort pkgs) $ \pkg -> do
-        (name, version) <- cabalNameVersion (pkgCabalFile pkg)
+        (name, version) <- pkgNameVersion pkg
         return (name ++ " == " ++ version)
     return (unlines constraints)
 
index 17ea482..0a0fe15 100644 (file)
@@ -9,8 +9,8 @@ import Utilities
 
 ghcCabalPackageArgs :: Args
 ghcCabalPackageArgs = stage0 ? package ghcCabal ? builder Ghc ? do
-    cabalDeps <- expr $ pkgDependencies cabal
-    (_, cabalVersion) <- expr $ cabalNameVersion (pkgCabalFile cabal)
+    cabalDeps <- expr $ stage1Dependencies cabal
+    (_, cabalVersion) <- expr $ pkgNameVersion cabal
     mconcat
         [ pure [ "-package " ++ pkgName pkg | pkg <- cabalDeps, pkg /= parsec ]
         , arg "--make"
index bc75320..0925d3c 100644 (file)
@@ -2,7 +2,7 @@ module Utilities (
     build, buildWithCmdOptions, buildWithResources, applyPatch, runBuilder,
     runBuilderWith, builderEnvironment, needBuilder, needLibrary,
     installDirectory, installData, installScript, installProgram, linkSymbolic,
-    contextDependencies, pkgDependencies, libraryTargets, topsortPackages,
+    contextDependencies, stage1Dependencies, libraryTargets, topsortPackages,
     packageDependenciesGenerator
     ) where
 
@@ -191,7 +191,7 @@ packageDependenciesGenerator _ = do
         exists <- doesFileExist (pkgCabalFile pkg)
         if not exists then return (pkgName pkg)
         else do
-            deps <- nubOrd . sort <$> cabalDependencies (pkgCabalFile pkg)
+            deps <- nubOrd . sort <$> pkgDependencies pkg
             return . unwords $ pkgName pkg : (deps \\ [pkgName pkg])
     return (unlines pkgDeps)
 
@@ -200,7 +200,7 @@ packageDependenciesGenerator _ = do
 -- The only subtlety here is that we never depend on packages built in 'Stage2'
 -- or later, therefore the stage of the resulting dependencies is bounded from
 -- above at 'Stage1'. To compute package dependencies we scan package cabal
--- files, see 'cabalDependencies' defined in "Hadrian.Haskell.Cabal".
+-- files, see 'pkgDependencies' defined in "Hadrian.Haskell.Cabal".
 contextDependencies :: Context -> Action [Context]
 contextDependencies Context {..} = do
     let pkgContext = \pkg -> Context (min stage Stage1) pkg way
@@ -211,8 +211,9 @@ contextDependencies Context {..} = do
     return . map pkgContext $ intersectOrd (compare . pkgName) pkgs deps
 
 -- | Lookup dependencies of a 'Package' in the vanilla Stage1 context.
-pkgDependencies :: Package -> Action [Package]
-pkgDependencies = fmap (map Context.package) . contextDependencies . vanillaContext Stage1
+stage1Dependencies :: Package -> Action [Package]
+stage1Dependencies =
+    fmap (map Context.package) . contextDependencies . vanillaContext Stage1
 
 -- | Given a library 'Package' this action computes all of its targets.
 libraryTargets :: Context -> Action [FilePath]
@@ -234,7 +235,7 @@ needLibrary cs = need =<< concatMapM libraryTargets cs
 -- | Topological sort of packages according to their dependencies.
 topsortPackages :: [Package] -> Action [Package]
 topsortPackages pkgs = do
-    elems <- mapM (\p -> (p,) <$> pkgDependencies p) pkgs
+    elems <- mapM (\p -> (p,) <$> stage1Dependencies p) pkgs
     return $ map fst $ topSort elems
   where
     annotateInDeg es e =