packages feed

ghc-check 0.2.0.0 → 0.3.0.0

raw patch · 6 files changed

+135/−89 lines, 6 filesdep +filepathdep +processPVP ok

version bump matches the API change (PVP)

Dependencies added: filepath, process

API changes (from Hackage documentation)

- GHC.Check: checkGhcVersion :: Ghc VersionCheck
- GHC.Check: compileTimeVersion :: IO FilePath -> String -> TExpQ Version
- GHC.Check: ghcCompileTimeVersion :: Version
- GHC.Check: runTimeVersion :: Ghc (Maybe Version)
- GHC.Check.Internal: compileTimeVersion :: IO FilePath -> String -> TExpQ Version
- GHC.Check.Internal: getGhcVersion :: Ghc (Maybe Version)
- GHC.Check.Internal: getPackageVersion :: String -> Ghc (Maybe Version)
- GHC.Check.Internal: getPackageVersionIO :: FilePath -> String -> IO Version
- GHC.Check.Internal: guessLibdir :: IO FilePath
+ GHC.Check: Failure :: String -> VersionCheck
+ GHC.Check: makeGhcVersionChecker :: IO (Maybe FilePath) -> TExpQ (IO VersionCheck)
+ GHC.Check.Executable: getGhcVersion :: FilePath -> IO Version
+ GHC.Check.Executable: guessExecutablePathFromLibdir :: FilePath -> FilePath
+ GHC.Check.Executable: trim :: String -> String
+ GHC.Check.PackageDb: getPackageVersion :: String -> Ghc (Maybe Version)
+ GHC.Check.PackageDb: getPackageVersionIO :: FilePath -> String -> IO (Maybe Version)
+ GHC.Check.Util: guessLibdir :: IO FilePath
+ GHC.Check.Util: liftVersion :: Version -> TExpQ Version
- GHC.Check: Mismatch :: Version -> Maybe Version -> VersionCheck
+ GHC.Check: Mismatch :: !Version -> !Version -> VersionCheck
- GHC.Check: [compileTime] :: VersionCheck -> Version
+ GHC.Check: [compileTime] :: VersionCheck -> !Version
- GHC.Check: [runTime] :: VersionCheck -> Maybe Version
+ GHC.Check: [runTime] :: VersionCheck -> !Version

Files

ghc-check.cabal view
@@ -1,7 +1,7 @@ cabal-version:       1.20 build-type:          Simple name:                ghc-check-version:             0.2.0.0+version:             0.3.0.0 synopsis:            detect mismatches between compile-time and run-time versions of the ghc api description:         detect mismatches between compile-time and run-time versions of the ghc api bug-reports:         https://github.com/pepeiborra/ghc-check/issues@@ -13,10 +13,15 @@ extra-source-files:  README.md  library-  exposed-modules:     GHC.Check, GHC.Check.Internal+  exposed-modules:     GHC.Check,+                       GHC.Check.Executable+                       GHC.Check.PackageDb+                       GHC.Check.Util   build-depends:       base >=4.10.0.0 && < 5.0,+                       filepath,                        ghc,                        ghc-paths,+                       process,                        template-haskell,                        transformers   hs-source-dirs:      src
src/GHC/Check.hs view
@@ -1,37 +1,53 @@ {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-} module GHC.Check ( VersionCheck(..)-, checkGhcVersion-, compileTimeVersion-, ghcCompileTimeVersion-, runTimeVersion+, makeGhcVersionChecker ) where +import           Control.Exception+import           Data.Maybe import           Data.Version               (Version) import           GHC-import           GHC.Check.Internal---- | Returns the compile-time version of the @ghc@ package.---   Uses 'guessLibdir' to find the GHC lib dir-ghcCompileTimeVersion :: Version-ghcCompileTimeVersion = $$(compileTimeVersion guessLibdir "ghc")---- | Returns the run-time version of the @ghc@ package in the package database-runTimeVersion :: Ghc (Maybe Version)-runTimeVersion = getGhcVersion+import           GHC.Check.Executable (getGhcVersion, guessExecutablePathFromLibdir)+import           GHC.Check.PackageDb  (getPackageVersionIO)+import           GHC.Check.Util       (liftVersion, guessLibdir)+import           Language.Haskell.TH+import           Language.Haskell.TH.Syntax  data VersionCheck     = Match-    | Mismatch { compileTime :: Version-               , runTime     :: Maybe Version+    | Mismatch { compileTime :: !Version+               , runTime     :: !Version                }+    | Failure String     deriving (Eq, Show) --- | Checks if the run-time version of the @ghc@ package matches the compile-time version.---   To be able to specify a custom libdir, inline this logic in your program.-checkGhcVersion :: Ghc VersionCheck-checkGhcVersion = do-    v <- getGhcVersion-    return $ if v == Just ghcCompileTimeVersion-        then GHC.Check.Match-        else Mismatch ghcCompileTimeVersion v+-- | A GHC version retrieved from the ghc executable+ghcRunTimeVersion :: IO Version+ghcRunTimeVersion = do+    libdir <- guessLibdir+    getGhcVersion (guessExecutablePathFromLibdir libdir)++-- | Checks if the run-time version of the @ghc@ package matches the given version.+checkGhcVersion :: Version -> IO VersionCheck+checkGhcVersion expectedVersion = handleErrors $ do+    v <- ghcRunTimeVersion+    return $ if v == expectedVersion+                then GHC.Check.Match+                else Mismatch expectedVersion v+    where+        handleErrors = flip catches+            [Handler (throwIO @SomeAsyncException)+            ,Handler (pure . Failure . show @SomeException)+            ]++-- | @makeGhcVersionChecker libdir@ returns a computation to check the run-time+--   version of ghc against the compile-time version.+makeGhcVersionChecker :: IO (Maybe FilePath) -> TExpQ (IO VersionCheck)+makeGhcVersionChecker getLibdir = do+    compileTimeVersion <- runIO $ do+        libdir <- maybe guessLibdir return =<< getLibdir+        mbVersion <- getPackageVersionIO libdir "ghc"+        return $ fromMaybe (error "unreachable - the ghc package is a Cabal dependency") mbVersion+    [|| checkGhcVersion $$(liftVersion compileTimeVersion) ||]
+ src/GHC/Check/Executable.hs view
@@ -0,0 +1,27 @@+{- | Discover the GHC version by querying the GHC executable++ -}+module GHC.Check.Executable where++import Data.Version+import GHC.Check.Util+import System.FilePath+import System.Process+import Text.ParserCombinators.ReadP+import Data.Char (isSpace)+import Data.List (dropWhileEnd)++-- | Takes a path to the GHC binary to query.+--   Throws if anything goes wrong.+getGhcVersion :: FilePath -> IO Version+getGhcVersion fp = do+    out <- readProcess fp ["--numeric-version"] ""+    case readP_to_S (parseVersion <* eof) (trim out) of+        [(v, "")] -> return v+        _ -> error $ "Failed to parse GHC version: " <> out++trim :: String -> String+trim = dropWhileEnd isSpace . dropWhile isSpace++guessExecutablePathFromLibdir :: FilePath -> FilePath+guessExecutablePathFromLibdir fp = fp </> "bin" </> "ghc"
− src/GHC/Check/Internal.hs
@@ -1,63 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-module GHC.Check.Internal where--import           Control.Monad.Trans.Class as Monad (MonadTrans (lift))-import           Data.Maybe                (fromMaybe)-import           Data.String               (IsString (fromString))-import           Data.Version              (Version)-import           GHC-import           GHC.Exts                   (IsList (fromList), toList)-import qualified GHC.Paths-import           Language.Haskell.TH-import           Language.Haskell.TH.Syntax as TH (TExp(TExp), lift)-import           Maybes                    (MaybeT (MaybeT), runMaybeT)-import           Module                    (componentIdToInstalledUnitId)-import           PackageConfig             (PackageName (PackageName))-import           Packages                  (lookupInstalledPackage, lookupPackageName)-import           Packages                  (InstalledPackageInfo (packageVersion))-import           System.Environment        (lookupEnv)---- | Look up the GHC lib dir in the NIX environment, then in the 'GHC.Paths'-guessLibdir :: IO FilePath-guessLibdir = fromMaybe GHC.Paths.libdir <$> lookupEnv "NIX_GHC_LIBDIR"---- | @getPackageVersion p@ returns the version of package @p@ in---     the package database-getPackageVersion :: String -> Ghc (Maybe Version)-getPackageVersion packageName = runMaybeT $ do-    dflags <- Monad.lift getSessionDynFlags-    component <- MaybeT $ return $ lookupPackageName dflags $ PackageName $ fromString packageName-    p <- MaybeT $ return $ lookupInstalledPackage dflags (componentIdToInstalledUnitId component)-    return $ packageVersion p---- | Returns the version of the @ghc@ package in the environment package database-getGhcVersion :: Ghc (Maybe Version)-getGhcVersion = getPackageVersion "ghc"---- | @getPackageVersionIO ghc-libdir p@ returns the version of package @p@---   in the default package database-getPackageVersionIO :: FilePath -> String -> IO Version-getPackageVersionIO libdir package = runGhc (Just libdir) $ do-    -- initialize the Ghc session-    -- there's probably a beteter way to do this.-    dflags <- getSessionDynFlags-    _ <- setSessionDynFlags dflags--    ver <- getPackageVersion package-    case ver of-        Just v  ->-            return v-        Nothing ->-            error $ "Cannot find " <> package <> " in the package database at " <> libdir---- | @compileTimeVersion get-libdir p@ returns the version of package @p@ in---   the compile-time package database.-compileTimeVersion :: IO FilePath -> String -> TExpQ Version-compileTimeVersion getLibdir package = do-    ver <- runIO $ do-        libdir <- getLibdir-        v <- getPackageVersionIO libdir package-        return (toList v)-    verLifted <- TH.lift (toList ver)-    [|| fromList $$(pure $ TExp verLifted) ||]
+ src/GHC/Check/PackageDb.hs view
@@ -0,0 +1,41 @@++{- | Discover the GHC version via the package database. Requirements:++     * the package database must be compatible, which is usually not the case+       across major ghc versions.++     * the 'ghc' package is registered, which is not always the case.+ -}+module GHC.Check.PackageDb where++import           Control.Monad.Trans.Class as Monad (MonadTrans (lift))+import           Data.Maybe                (fromMaybe)+import           Data.String               (IsString (fromString))+import           Data.Version              (Version)+import           GHC                       (setSessionDynFlags, runGhc, getSessionDynFlags, Ghc)+import           GHC.Exts                  (IsList (fromList), toList)+import           Maybes                    (MaybeT (MaybeT), runMaybeT)+import           Module                    (componentIdToInstalledUnitId)+import           PackageConfig             (PackageName (PackageName))+import           Packages                  (lookupInstalledPackage, lookupPackageName)+import           Packages                  (InstalledPackageInfo (packageVersion))++-- | @getPackageVersion p@ returns the version of package @p@ in+--     the package database+getPackageVersion :: String -> Ghc (Maybe Version)+getPackageVersion packageName = runMaybeT $ do+    dflags <- Monad.lift getSessionDynFlags+    component <- MaybeT $ return $ lookupPackageName dflags $ PackageName $ fromString packageName+    p <- MaybeT $ return $ lookupInstalledPackage dflags (componentIdToInstalledUnitId component)+    return $ packageVersion p++-- | @getPackageVersionIO ghc-libdir p@ returns the version of package @p@+--   in the default package database+getPackageVersionIO :: FilePath -> String -> IO (Maybe Version)+getPackageVersionIO libdir package = runGhc (Just libdir) $ do+    -- initialize the Ghc session+    -- there's probably a beteter way to do this.+    dflags <- getSessionDynFlags+    _ <- setSessionDynFlags dflags++    getPackageVersion package
+ src/GHC/Check/Util.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE TemplateHaskell #-}+module GHC.Check.Util where+++import           Data.Maybe+import           Data.Version+import           GHC.Exts                   (IsList (fromList), toList)+import qualified GHC.Paths+import           Language.Haskell.TH+import           Language.Haskell.TH.Syntax as TH+import           System.Environment (lookupEnv)++-- | Look up the GHC lib dir in the NIX environment, then in the 'GHC.Paths'+guessLibdir :: IO FilePath+guessLibdir = fromMaybe GHC.Paths.libdir <$> lookupEnv "NIX_GHC_LIBDIR"++liftVersion :: Version -> TExpQ Version+liftVersion ver = do+    verLifted <- TH.lift (toList ver)+    [|| fromList $$(pure $ TExp verLifted) ||]