Merge branch 'master' of https://github.com/robeverest/ghc-mod
Conflicts: Language/Haskell/GhcMod/CabalConfig.hs
This commit is contained in:
commit
690a64f5b5
@ -17,7 +17,7 @@ import Language.Haskell.GhcMod.Gap (benchmarkBuildInfo, benchmarkTargets,
|
|||||||
import Language.Haskell.GhcMod.GhcPkg
|
import Language.Haskell.GhcMod.GhcPkg
|
||||||
import Language.Haskell.GhcMod.Types
|
import Language.Haskell.GhcMod.Types
|
||||||
|
|
||||||
import MonadUtils (MonadIO, liftIO)
|
import MonadUtils (liftIO)
|
||||||
import Control.Applicative ((<$>))
|
import Control.Applicative ((<$>))
|
||||||
import qualified Control.Exception as E
|
import qualified Control.Exception as E
|
||||||
import Control.Monad (filterM)
|
import Control.Monad (filterM)
|
||||||
@ -73,20 +73,22 @@ includeDirectories cdir wdir dirs = uniqueAndSort (extdirs ++ [cdir,wdir])
|
|||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
-- | Parse a cabal file and return a 'PackageDescription'.
|
-- | Parse a cabal file and return a 'PackageDescription'.
|
||||||
parseCabalFile :: (MonadIO m, Error e, MonadError e m)
|
parseCabalFile :: (IOish m, MonadError GhcModError m)
|
||||||
=> FilePath
|
=> Cradle
|
||||||
|
-> FilePath
|
||||||
-> m PackageDescription
|
-> m PackageDescription
|
||||||
parseCabalFile file = do
|
parseCabalFile cradle file = do
|
||||||
cid <- liftIO getGHCId
|
cid <- liftIO getGHCId
|
||||||
epgd <- liftIO $ readPackageDescription silent file
|
epgd <- liftIO $ readPackageDescription silent file
|
||||||
case toPkgDesc cid epgd of
|
flags <- cabalConfigFlags cradle
|
||||||
|
case toPkgDesc cid flags epgd of
|
||||||
Left deps -> fail $ show deps ++ " are not installed"
|
Left deps -> fail $ show deps ++ " are not installed"
|
||||||
Right (pd,_) -> if nullPkg pd
|
Right (pd,_) -> if nullPkg pd
|
||||||
then fail $ file ++ " is broken"
|
then fail $ file ++ " is broken"
|
||||||
else return pd
|
else return pd
|
||||||
where
|
where
|
||||||
toPkgDesc cid =
|
toPkgDesc cid flags =
|
||||||
finalizePackageDescription [] (const True) buildPlatform cid []
|
finalizePackageDescription flags (const True) buildPlatform cid []
|
||||||
nullPkg pd = name == ""
|
nullPkg pd = name == ""
|
||||||
where
|
where
|
||||||
PackageName name = C.pkgName (P.package pd)
|
PackageName name = C.pkgName (P.package pd)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
module Language.Haskell.GhcMod.CabalConfig (
|
module Language.Haskell.GhcMod.CabalConfig (
|
||||||
CabalConfig
|
CabalConfig
|
||||||
, cabalConfigDependencies
|
, cabalConfigDependencies
|
||||||
|
, cabalConfigFlags
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Language.Haskell.GhcMod.Error
|
import Language.Haskell.GhcMod.Error
|
||||||
@ -34,6 +35,7 @@ import Data.List (find,tails,isPrefixOf,isInfixOf,nub,stripPrefix)
|
|||||||
import Distribution.Package (InstalledPackageId(..)
|
import Distribution.Package (InstalledPackageId(..)
|
||||||
, PackageIdentifier(..)
|
, PackageIdentifier(..)
|
||||||
, PackageName(..))
|
, PackageName(..))
|
||||||
|
import Distribution.PackageDescription (FlagAssignment)
|
||||||
import Distribution.Simple.BuildPaths (defaultDistPref)
|
import Distribution.Simple.BuildPaths (defaultDistPref)
|
||||||
import Distribution.Simple.Configure (localBuildInfoFile)
|
import Distribution.Simple.Configure (localBuildInfoFile)
|
||||||
import Distribution.Simple.LocalBuildInfo (ComponentName)
|
import Distribution.Simple.LocalBuildInfo (ComponentName)
|
||||||
@ -152,6 +154,20 @@ configDependencies thisPkg config = map fromInstalledPackageId deps
|
|||||||
Right x -> x
|
Right x -> x
|
||||||
Left msg -> error $ "reading config " ++ f ++ " failed ("++msg++")"
|
Left msg -> error $ "reading config " ++ f ++ " failed ("++msg++")"
|
||||||
|
|
||||||
|
-- | Get the flag assignment from the local build info of the given cradle
|
||||||
|
cabalConfigFlags :: (IOish m, MonadError GhcModError m)
|
||||||
|
=> Cradle
|
||||||
|
-> m FlagAssignment
|
||||||
|
cabalConfigFlags cradle = do
|
||||||
|
config <- getConfig cradle
|
||||||
|
case configFlags config of
|
||||||
|
Right x -> return x
|
||||||
|
Left msg -> throwError (GMECabalFlags (GMEString msg))
|
||||||
|
|
||||||
|
-- | Extract the cabal flags from the 'CabalConfig'
|
||||||
|
configFlags :: CabalConfig -> Either String FlagAssignment
|
||||||
|
configFlags config = readEither =<< flip extractField "configConfigurationsFlags" =<< extractField config "configFlags"
|
||||||
|
|
||||||
-- | Find @field@ in 'CabalConfig'. Returns 'Left' containing a user readable
|
-- | Find @field@ in 'CabalConfig'. Returns 'Left' containing a user readable
|
||||||
-- error message with lots of context on failure.
|
-- error message with lots of context on failure.
|
||||||
extractField :: CabalConfig -> String -> Either String String
|
extractField :: CabalConfig -> String -> Either String String
|
||||||
|
@ -31,7 +31,7 @@ debugInfo = cradle >>= \c -> convert' =<< do
|
|||||||
simpleCompilerOption = options >>= \op ->
|
simpleCompilerOption = options >>= \op ->
|
||||||
return $ CompilerOptions (ghcUserOptions op) [] []
|
return $ CompilerOptions (ghcUserOptions op) [] []
|
||||||
fromCabalFile c = options >>= \opts -> do
|
fromCabalFile c = options >>= \opts -> do
|
||||||
pkgDesc <- parseCabalFile $ fromJust $ cradleCabalFile c
|
pkgDesc <- parseCabalFile c $ fromJust $ cradleCabalFile c
|
||||||
getCompilerOptions (ghcUserOptions opts) c pkgDesc
|
getCompilerOptions (ghcUserOptions opts) c pkgDesc
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
@ -18,6 +18,8 @@ data GhcModError = GMENoMsg
|
|||||||
-- 'fail' calls on GhcModT.
|
-- 'fail' calls on GhcModT.
|
||||||
| GMECabalConfigure GhcModError
|
| GMECabalConfigure GhcModError
|
||||||
-- ^ Configuring a cabal project failed.
|
-- ^ Configuring a cabal project failed.
|
||||||
|
| GMECabalFlags GhcModError
|
||||||
|
-- ^ Retrieval of the cabal configuration flags failed.
|
||||||
| GMEProcess [String] GhcModError
|
| GMEProcess [String] GhcModError
|
||||||
-- ^ Launching an operating system process failed. The first
|
-- ^ Launching an operating system process failed. The first
|
||||||
-- field is the command.
|
-- field is the command.
|
||||||
|
@ -204,7 +204,7 @@ initializeFlagsWithCradle opt c
|
|||||||
cabal = isJust mCradleFile
|
cabal = isJust mCradleFile
|
||||||
ghcopts = ghcUserOptions opt
|
ghcopts = ghcUserOptions opt
|
||||||
withCabal = do
|
withCabal = do
|
||||||
pkgDesc <- parseCabalFile $ fromJust mCradleFile
|
pkgDesc <- parseCabalFile c $ fromJust mCradleFile
|
||||||
compOpts <- getCompilerOptions ghcopts c pkgDesc
|
compOpts <- getCompilerOptions ghcopts c pkgDesc
|
||||||
initSession CabalPkg opt compOpts
|
initSession CabalPkg opt compOpts
|
||||||
withSandbox = initSession SingleFile opt compOpts
|
withSandbox = initSession SingleFile opt compOpts
|
||||||
|
@ -34,6 +34,7 @@ Extra-Source-Files: ChangeLog
|
|||||||
test/data/broken-cabal/cabal.sandbox.config.in
|
test/data/broken-cabal/cabal.sandbox.config.in
|
||||||
test/data/broken-sandbox/*.cabal
|
test/data/broken-sandbox/*.cabal
|
||||||
test/data/broken-sandbox/cabal.sandbox.config
|
test/data/broken-sandbox/cabal.sandbox.config
|
||||||
|
test/data/cabal-flags/*.cabal
|
||||||
test/data/check-test-subdir/*.cabal
|
test/data/check-test-subdir/*.cabal
|
||||||
test/data/check-test-subdir/src/Check/Test/*.hs
|
test/data/check-test-subdir/src/Check/Test/*.hs
|
||||||
test/data/check-test-subdir/test/*.hs
|
test/data/check-test-subdir/test/*.hs
|
||||||
|
@ -149,6 +149,8 @@ main = flip E.catches handlers $ do
|
|||||||
hPutStrLn stderr msg
|
hPutStrLn stderr msg
|
||||||
Left (GMECabalConfigure msg) ->
|
Left (GMECabalConfigure msg) ->
|
||||||
hPutStrLn stderr $ "cabal configure failed: " ++ show msg
|
hPutStrLn stderr $ "cabal configure failed: " ++ show msg
|
||||||
|
Left (GMECabalFlags msg) ->
|
||||||
|
hPutStrLn stderr $ "retrieval of the cabal configuration flags failed: " ++ show msg
|
||||||
Left (GMEProcess cmd msg) ->
|
Left (GMEProcess cmd msg) ->
|
||||||
hPutStrLn stderr $
|
hPutStrLn stderr $
|
||||||
"launching operating system process `"++c++"` failed: " ++ show msg
|
"launching operating system process `"++c++"` failed: " ++ show msg
|
||||||
|
@ -10,6 +10,7 @@ import Language.Haskell.GhcMod.Types
|
|||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
|
import System.Process (readProcess)
|
||||||
|
|
||||||
import Dir
|
import Dir
|
||||||
import TestUtils
|
import TestUtils
|
||||||
@ -23,8 +24,10 @@ spec :: Spec
|
|||||||
spec = do
|
spec = do
|
||||||
describe "parseCabalFile" $ do
|
describe "parseCabalFile" $ do
|
||||||
it "throws an exception if the cabal file is broken" $ do
|
it "throws an exception if the cabal file is broken" $ do
|
||||||
shouldReturnError $
|
shouldReturnError $ do
|
||||||
runD' $ parseCabalFile "test/data/broken-cabal/broken.cabal"
|
withDirectory_ "test/data/broken-cabal" $ do
|
||||||
|
crdl <- findCradle
|
||||||
|
runD' $ parseCabalFile crdl "broken.cabal"
|
||||||
|
|
||||||
|
|
||||||
describe "getCompilerOptions" $ do
|
describe "getCompilerOptions" $ do
|
||||||
@ -32,7 +35,7 @@ spec = do
|
|||||||
cwd <- getCurrentDirectory
|
cwd <- getCurrentDirectory
|
||||||
withDirectory "test/data/subdir1/subdir2" $ \dir -> do
|
withDirectory "test/data/subdir1/subdir2" $ \dir -> do
|
||||||
crdl <- findCradle
|
crdl <- findCradle
|
||||||
pkgDesc <- runD $ parseCabalFile $ fromJust $ cradleCabalFile crdl
|
pkgDesc <- runD $ parseCabalFile crdl $ fromJust $ cradleCabalFile crdl
|
||||||
res <- runD $ getCompilerOptions [] crdl pkgDesc
|
res <- runD $ getCompilerOptions [] crdl pkgDesc
|
||||||
let res' = res {
|
let res' = res {
|
||||||
ghcOptions = ghcOptions res
|
ghcOptions = ghcOptions res
|
||||||
@ -47,18 +50,28 @@ spec = do
|
|||||||
|
|
||||||
describe "cabalDependPackages" $ do
|
describe "cabalDependPackages" $ do
|
||||||
it "extracts dependent packages" $ do
|
it "extracts dependent packages" $ do
|
||||||
pkgs <- cabalDependPackages . cabalAllBuildInfo <$> runD (parseCabalFile "test/data/cabalapi.cabal")
|
crdl <- findCradle' "test/data/"
|
||||||
|
pkgs <- cabalDependPackages . cabalAllBuildInfo <$> runD (parseCabalFile crdl "test/data/cabalapi.cabal")
|
||||||
pkgs `shouldBe` ["Cabal","base","template-haskell"]
|
pkgs `shouldBe` ["Cabal","base","template-haskell"]
|
||||||
|
it "uses non default flags" $ do
|
||||||
|
withDirectory_ "test/data/cabal-flags" $ do
|
||||||
|
crdl <- findCradle
|
||||||
|
_ <- readProcess "cabal" ["configure", "-ftest-flag"] ""
|
||||||
|
pkgs <- cabalDependPackages . cabalAllBuildInfo <$> runD (parseCabalFile crdl "cabal-flags.cabal")
|
||||||
|
pkgs `shouldBe` ["Cabal","base"]
|
||||||
|
|
||||||
describe "cabalSourceDirs" $ do
|
describe "cabalSourceDirs" $ do
|
||||||
it "extracts all hs-source-dirs" $ do
|
it "extracts all hs-source-dirs" $ do
|
||||||
dirs <- cabalSourceDirs . cabalAllBuildInfo <$> runD (parseCabalFile "test/data/check-test-subdir/check-test-subdir.cabal")
|
crdl <- findCradle' "test/data/check-test-subdir"
|
||||||
|
dirs <- cabalSourceDirs . cabalAllBuildInfo <$> runD (parseCabalFile crdl "test/data/check-test-subdir/check-test-subdir.cabal")
|
||||||
dirs `shouldBe` ["src", "test"]
|
dirs `shouldBe` ["src", "test"]
|
||||||
it "extracts all hs-source-dirs including \".\"" $ do
|
it "extracts all hs-source-dirs including \".\"" $ do
|
||||||
dirs <- cabalSourceDirs . cabalAllBuildInfo <$> runD (parseCabalFile "test/data/cabalapi.cabal")
|
crdl <- findCradle' "test/data/"
|
||||||
|
dirs <- cabalSourceDirs . cabalAllBuildInfo <$> runD (parseCabalFile crdl "test/data/cabalapi.cabal")
|
||||||
dirs `shouldBe` [".", "test"]
|
dirs `shouldBe` [".", "test"]
|
||||||
|
|
||||||
describe "cabalAllBuildInfo" $ do
|
describe "cabalAllBuildInfo" $ do
|
||||||
it "extracts build info" $ do
|
it "extracts build info" $ do
|
||||||
info <- cabalAllBuildInfo <$> runD (parseCabalFile "test/data/cabalapi.cabal")
|
crdl <- findCradle' "test/data/"
|
||||||
|
info <- cabalAllBuildInfo <$> runD (parseCabalFile crdl "test/data/cabalapi.cabal")
|
||||||
show info `shouldBe` "[BuildInfo {buildable = True, buildTools = [], cppOptions = [], ccOptions = [], ldOptions = [], pkgconfigDepends = [], frameworks = [], cSources = [], hsSourceDirs = [\".\"], otherModules = [ModuleName [\"Browse\"],ModuleName [\"CabalApi\"],ModuleName [\"Cabal\"],ModuleName [\"CabalDev\"],ModuleName [\"Check\"],ModuleName [\"ErrMsg\"],ModuleName [\"Flag\"],ModuleName [\"GHCApi\"],ModuleName [\"GHCChoice\"],ModuleName [\"Gap\"],ModuleName [\"Info\"],ModuleName [\"Lang\"],ModuleName [\"Lint\"],ModuleName [\"List\"],ModuleName [\"Paths_ghc_mod\"],ModuleName [\"Types\"]], defaultLanguage = Nothing, otherLanguages = [], defaultExtensions = [], otherExtensions = [], oldExtensions = [], extraLibs = [], extraLibDirs = [], includeDirs = [], includes = [], installIncludes = [], options = [(GHC,[\"-Wall\"])], ghcProfOptions = [], ghcSharedOptions = [], customFieldsBI = [], targetBuildDepends = [Dependency (PackageName \"Cabal\") (UnionVersionRanges (ThisVersion (Version {versionBranch = [1,10], versionTags = []})) (LaterVersion (Version {versionBranch = [1,10], versionTags = []}))),Dependency (PackageName \"base\") (IntersectVersionRanges (UnionVersionRanges (ThisVersion (Version {versionBranch = [4,0], versionTags = []})) (LaterVersion (Version {versionBranch = [4,0], versionTags = []}))) (EarlierVersion (Version {versionBranch = [5], versionTags = []}))),Dependency (PackageName \"template-haskell\") AnyVersion]},BuildInfo {buildable = True, buildTools = [], cppOptions = [], ccOptions = [], ldOptions = [], pkgconfigDepends = [], frameworks = [], cSources = [], hsSourceDirs = [\"test\",\".\"], otherModules = [ModuleName [\"Expectation\"],ModuleName [\"BrowseSpec\"],ModuleName [\"CabalApiSpec\"],ModuleName [\"FlagSpec\"],ModuleName [\"LangSpec\"],ModuleName [\"LintSpec\"],ModuleName [\"ListSpec\"]], defaultLanguage = Nothing, otherLanguages = [], defaultExtensions = [], otherExtensions = [], oldExtensions = [], extraLibs = [], extraLibDirs = [], includeDirs = [], includes = [], installIncludes = [], options = [], ghcProfOptions = [], ghcSharedOptions = [], customFieldsBI = [], targetBuildDepends = [Dependency (PackageName \"Cabal\") (UnionVersionRanges (ThisVersion (Version {versionBranch = [1,10], versionTags = []})) (LaterVersion (Version {versionBranch = [1,10], versionTags = []}))),Dependency (PackageName \"base\") (IntersectVersionRanges (UnionVersionRanges (ThisVersion (Version {versionBranch = [4,0], versionTags = []})) (LaterVersion (Version {versionBranch = [4,0], versionTags = []}))) (EarlierVersion (Version {versionBranch = [5], versionTags = []})))]}]"
|
show info `shouldBe` "[BuildInfo {buildable = True, buildTools = [], cppOptions = [], ccOptions = [], ldOptions = [], pkgconfigDepends = [], frameworks = [], cSources = [], hsSourceDirs = [\".\"], otherModules = [ModuleName [\"Browse\"],ModuleName [\"CabalApi\"],ModuleName [\"Cabal\"],ModuleName [\"CabalDev\"],ModuleName [\"Check\"],ModuleName [\"ErrMsg\"],ModuleName [\"Flag\"],ModuleName [\"GHCApi\"],ModuleName [\"GHCChoice\"],ModuleName [\"Gap\"],ModuleName [\"Info\"],ModuleName [\"Lang\"],ModuleName [\"Lint\"],ModuleName [\"List\"],ModuleName [\"Paths_ghc_mod\"],ModuleName [\"Types\"]], defaultLanguage = Nothing, otherLanguages = [], defaultExtensions = [], otherExtensions = [], oldExtensions = [], extraLibs = [], extraLibDirs = [], includeDirs = [], includes = [], installIncludes = [], options = [(GHC,[\"-Wall\"])], ghcProfOptions = [], ghcSharedOptions = [], customFieldsBI = [], targetBuildDepends = [Dependency (PackageName \"Cabal\") (UnionVersionRanges (ThisVersion (Version {versionBranch = [1,10], versionTags = []})) (LaterVersion (Version {versionBranch = [1,10], versionTags = []}))),Dependency (PackageName \"base\") (IntersectVersionRanges (UnionVersionRanges (ThisVersion (Version {versionBranch = [4,0], versionTags = []})) (LaterVersion (Version {versionBranch = [4,0], versionTags = []}))) (EarlierVersion (Version {versionBranch = [5], versionTags = []}))),Dependency (PackageName \"template-haskell\") AnyVersion]},BuildInfo {buildable = True, buildTools = [], cppOptions = [], ccOptions = [], ldOptions = [], pkgconfigDepends = [], frameworks = [], cSources = [], hsSourceDirs = [\"test\",\".\"], otherModules = [ModuleName [\"Expectation\"],ModuleName [\"BrowseSpec\"],ModuleName [\"CabalApiSpec\"],ModuleName [\"FlagSpec\"],ModuleName [\"LangSpec\"],ModuleName [\"LintSpec\"],ModuleName [\"ListSpec\"]], defaultLanguage = Nothing, otherLanguages = [], defaultExtensions = [], otherExtensions = [], oldExtensions = [], extraLibs = [], extraLibDirs = [], includeDirs = [], includes = [], installIncludes = [], options = [], ghcProfOptions = [], ghcSharedOptions = [], customFieldsBI = [], targetBuildDepends = [Dependency (PackageName \"Cabal\") (UnionVersionRanges (ThisVersion (Version {versionBranch = [1,10], versionTags = []})) (LaterVersion (Version {versionBranch = [1,10], versionTags = []}))),Dependency (PackageName \"base\") (IntersectVersionRanges (UnionVersionRanges (ThisVersion (Version {versionBranch = [4,0], versionTags = []})) (LaterVersion (Version {versionBranch = [4,0], versionTags = []}))) (EarlierVersion (Version {versionBranch = [5], versionTags = []})))]}]"
|
||||||
|
14
test/data/cabal-flags/cabal-flags.cabal
Normal file
14
test/data/cabal-flags/cabal-flags.cabal
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
name: cabal-flags
|
||||||
|
version: 0.1.0
|
||||||
|
build-type: Simple
|
||||||
|
cabal-version: >= 1.8
|
||||||
|
|
||||||
|
flag test-flag
|
||||||
|
default: False
|
||||||
|
|
||||||
|
library
|
||||||
|
build-depends: base == 4.*
|
||||||
|
|
||||||
|
if flag(test-flag)
|
||||||
|
build-depends: Cabal >= 1.10
|
||||||
|
|
Loading…
Reference in New Issue
Block a user