Fix race condition in stack support code
This commit is contained in:
parent
12d65ba11f
commit
211b957451
@ -3,7 +3,7 @@
|
|||||||
module Language.Haskell.GhcMod (
|
module Language.Haskell.GhcMod (
|
||||||
-- * Cradle
|
-- * Cradle
|
||||||
Cradle(..)
|
Cradle(..)
|
||||||
, ProjectType(..)
|
, Project(..)
|
||||||
, findCradle
|
, findCradle
|
||||||
-- * Options
|
-- * Options
|
||||||
, Options(..)
|
, Options(..)
|
||||||
|
@ -20,7 +20,6 @@ module Language.Haskell.GhcMod.CabalHelper
|
|||||||
( getComponents
|
( getComponents
|
||||||
, getGhcMergedPkgOptions
|
, getGhcMergedPkgOptions
|
||||||
, getCabalPackageDbStack
|
, getCabalPackageDbStack
|
||||||
, getStackPackageDbStack
|
|
||||||
, prepareCabalHelper
|
, prepareCabalHelper
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
@ -44,7 +43,6 @@ import Language.Haskell.GhcMod.Logging
|
|||||||
import Language.Haskell.GhcMod.Output
|
import Language.Haskell.GhcMod.Output
|
||||||
import Language.Haskell.GhcMod.CustomPackageDb
|
import Language.Haskell.GhcMod.CustomPackageDb
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import System.Directory (findExecutable)
|
|
||||||
import System.Process
|
import System.Process
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import Prelude hiding ((.))
|
import Prelude hiding ((.))
|
||||||
@ -136,30 +134,18 @@ prepareCabalHelper = do
|
|||||||
let projdir = cradleRootDir crdl
|
let projdir = cradleRootDir crdl
|
||||||
distdir = projdir </> cradleDistDir crdl
|
distdir = projdir </> cradleDistDir crdl
|
||||||
readProc <- gmReadProcess
|
readProc <- gmReadProcess
|
||||||
when (cradleProjectType crdl == CabalProject || cradleProjectType crdl == StackProject) $
|
when (isCabalHelperProject $ cradleProject crdl) $
|
||||||
withCabal $ liftIO $ prepare readProc projdir distdir
|
withCabal $ liftIO $ prepare readProc projdir distdir
|
||||||
|
|
||||||
getStackPackageDbStack :: IOish m => m [GhcPkgDb]
|
|
||||||
getStackPackageDbStack = do
|
|
||||||
mstack <- liftIO $ findExecutable "stack"
|
|
||||||
case mstack of
|
|
||||||
Nothing -> return []
|
|
||||||
Just stack -> do
|
|
||||||
snapshotDb <- liftIO $ readProcess stack ["path", "--snapshot-pkg-db"] ""
|
|
||||||
localDb <- liftIO $ readProcess stack ["path", "--local-pkg-db"] ""
|
|
||||||
return $ map (PackageDb . takeWhile (/='\n')) [snapshotDb, localDb]
|
|
||||||
|
|
||||||
patchStackPrograms :: (IOish m, GmOut m) => Cradle -> Programs -> m Programs
|
patchStackPrograms :: (IOish m, GmOut m) => Cradle -> Programs -> m Programs
|
||||||
patchStackPrograms crdl progs
|
patchStackPrograms Cradle { cradleProject = (StackProject senv) } progs = do
|
||||||
| cradleProjectType crdl /= StackProject = return progs
|
Just ghc <- getStackGhcPath senv
|
||||||
patchStackPrograms crdl progs = do
|
Just ghcPkg <- getStackGhcPkgPath senv
|
||||||
let projdir = cradleRootDir crdl
|
|
||||||
Just ghc <- getStackGhcPath projdir
|
|
||||||
Just ghcPkg <- getStackGhcPkgPath projdir
|
|
||||||
return $ progs {
|
return $ progs {
|
||||||
ghcProgram = ghc
|
ghcProgram = ghc
|
||||||
, ghcPkgProgram = ghcPkg
|
, ghcPkgProgram = ghcPkg
|
||||||
}
|
}
|
||||||
|
patchStackPrograms _crdl progs = return progs
|
||||||
|
|
||||||
withCabal :: (IOish m, GmEnv m, GmOut m, GmLog m) => m a -> m a
|
withCabal :: (IOish m, GmEnv m, GmOut m, GmLog m) => m a -> m a
|
||||||
withCabal action = do
|
withCabal action = do
|
||||||
@ -188,7 +174,7 @@ withCabal action = do
|
|||||||
|
|
||||||
Nothing -> return False
|
Nothing -> return False
|
||||||
|
|
||||||
projType <- cradleProjectType <$> cradle
|
proj <- cradleProject <$> cradle
|
||||||
|
|
||||||
when (isSetupConfigOutOfDate mCabalFile mCabalConfig) $
|
when (isSetupConfigOutOfDate mCabalFile mCabalConfig) $
|
||||||
gmLog GmDebug "" $ strDoc $ "setup configuration is out of date, reconfiguring Cabal project."
|
gmLog GmDebug "" $ strDoc $ "setup configuration is out of date, reconfiguring Cabal project."
|
||||||
@ -202,14 +188,14 @@ withCabal action = do
|
|||||||
when ( isSetupConfigOutOfDate mCabalFile mCabalConfig
|
when ( isSetupConfigOutOfDate mCabalFile mCabalConfig
|
||||||
|| pkgDbStackOutOfSync
|
|| pkgDbStackOutOfSync
|
||||||
|| isSetupConfigOutOfDate mCabalSandboxConfig mCabalConfig) $
|
|| isSetupConfigOutOfDate mCabalSandboxConfig mCabalConfig) $
|
||||||
case projType of
|
case proj of
|
||||||
CabalProject ->
|
CabalProject ->
|
||||||
cabalReconfigure readProc (optPrograms opts) crdl projdir distdir
|
cabalReconfigure readProc (optPrograms opts) crdl projdir distdir
|
||||||
StackProject ->
|
StackProject {} ->
|
||||||
|
|
||||||
stackReconfigure crdl (optPrograms opts)
|
stackReconfigure crdl (optPrograms opts)
|
||||||
_ ->
|
_ ->
|
||||||
error $ "withCabal: unsupported project type: " ++ show projType
|
error $ "withCabal: unsupported project type: " ++ show proj
|
||||||
|
|
||||||
action
|
action
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ cabalCradle wdir = do
|
|||||||
let cabalDir = takeDirectory cabalFile
|
let cabalDir = takeDirectory cabalFile
|
||||||
|
|
||||||
return Cradle {
|
return Cradle {
|
||||||
cradleProjectType = CabalProject
|
cradleProject = CabalProject
|
||||||
, cradleCurrentDir = wdir
|
, cradleCurrentDir = wdir
|
||||||
, cradleRootDir = cabalDir
|
, cradleRootDir = cabalDir
|
||||||
, cradleTempDir = error "tmpDir"
|
, cradleTempDir = error "tmpDir"
|
||||||
@ -89,22 +89,22 @@ stackCradle wdir = do
|
|||||||
-- rather than stack, or maybe that's just me ;)
|
-- rather than stack, or maybe that's just me ;)
|
||||||
whenM (liftIO $ doesFileExist $ setupConfigPath "dist") $ mzero
|
whenM (liftIO $ doesFileExist $ setupConfigPath "dist") $ mzero
|
||||||
|
|
||||||
distDir <- MaybeT $ getStackDistDir cabalDir
|
senv <- MaybeT $ getStackEnv cabalDir
|
||||||
|
|
||||||
return Cradle {
|
return Cradle {
|
||||||
cradleProjectType = StackProject
|
cradleProject = StackProject senv
|
||||||
, cradleCurrentDir = wdir
|
, cradleCurrentDir = wdir
|
||||||
, cradleRootDir = cabalDir
|
, cradleRootDir = cabalDir
|
||||||
, cradleTempDir = error "tmpDir"
|
, cradleTempDir = error "tmpDir"
|
||||||
, cradleCabalFile = Just cabalFile
|
, cradleCabalFile = Just cabalFile
|
||||||
, cradleDistDir = distDir
|
, cradleDistDir = seDistDir senv
|
||||||
}
|
}
|
||||||
|
|
||||||
sandboxCradle :: IOish m => FilePath -> MaybeT m Cradle
|
sandboxCradle :: IOish m => FilePath -> MaybeT m Cradle
|
||||||
sandboxCradle wdir = do
|
sandboxCradle wdir = do
|
||||||
sbDir <- MaybeT $ liftIO $ findCabalSandboxDir wdir
|
sbDir <- MaybeT $ liftIO $ findCabalSandboxDir wdir
|
||||||
return Cradle {
|
return Cradle {
|
||||||
cradleProjectType = SandboxProject
|
cradleProject = SandboxProject
|
||||||
, cradleCurrentDir = wdir
|
, cradleCurrentDir = wdir
|
||||||
, cradleRootDir = sbDir
|
, cradleRootDir = sbDir
|
||||||
, cradleTempDir = error "tmpDir"
|
, cradleTempDir = error "tmpDir"
|
||||||
@ -115,7 +115,7 @@ sandboxCradle wdir = do
|
|||||||
plainCradle :: IOish m => FilePath -> MaybeT m Cradle
|
plainCradle :: IOish m => FilePath -> MaybeT m Cradle
|
||||||
plainCradle wdir = do
|
plainCradle wdir = do
|
||||||
return $ Cradle {
|
return $ Cradle {
|
||||||
cradleProjectType = PlainProject
|
cradleProject = PlainProject
|
||||||
, cradleCurrentDir = wdir
|
, cradleCurrentDir = wdir
|
||||||
, cradleRootDir = wdir
|
, cradleRootDir = wdir
|
||||||
, cradleTempDir = error "tmpDir"
|
, cradleTempDir = error "tmpDir"
|
||||||
|
@ -26,9 +26,9 @@ debugInfo = do
|
|||||||
Cradle {..} <- cradle
|
Cradle {..} <- cradle
|
||||||
|
|
||||||
cabal <-
|
cabal <-
|
||||||
case cradleProjectType of
|
case cradleProject of
|
||||||
CabalProject -> cabalDebug
|
CabalProject -> cabalDebug
|
||||||
StackProject -> (++) <$> stackPaths <*> cabalDebug
|
StackProject {} -> (++) <$> stackPaths <*> cabalDebug
|
||||||
_ -> return []
|
_ -> return []
|
||||||
|
|
||||||
pkgOpts <- packageGhcOptions
|
pkgOpts <- packageGhcOptions
|
||||||
@ -45,9 +45,9 @@ debugInfo = do
|
|||||||
|
|
||||||
stackPaths :: IOish m => GhcModT m [String]
|
stackPaths :: IOish m => GhcModT m [String]
|
||||||
stackPaths = do
|
stackPaths = do
|
||||||
Cradle {..} <- cradle
|
Cradle { cradleProject = StackProject senv } <- cradle
|
||||||
Just ghc <- getStackGhcPath cradleRootDir
|
ghc <- getStackGhcPath senv
|
||||||
Just ghcPkg <- getStackGhcPkgPath cradleRootDir
|
ghcPkg <- getStackGhcPkgPath senv
|
||||||
return $
|
return $
|
||||||
[ "Stack ghc executable: " ++ show ghc
|
[ "Stack ghc executable: " ++ show ghc
|
||||||
, "Stack ghc-pkg executable:" ++ show ghcPkg
|
, "Stack ghc-pkg executable:" ++ show ghcPkg
|
||||||
@ -64,7 +64,7 @@ cabalDebug = do
|
|||||||
|
|
||||||
return $
|
return $
|
||||||
[ "Cabal file: " ++ show cradleCabalFile
|
[ "Cabal file: " ++ show cradleCabalFile
|
||||||
, "Cabal Project Type: " ++ show cradleProjectType
|
, "Project: " ++ show cradleProject
|
||||||
, "Cabal entrypoints:\n" ++ render (nest 4 $
|
, "Cabal entrypoints:\n" ++ render (nest 4 $
|
||||||
mapDoc gmComponentNameDoc smpDoc entrypoints)
|
mapDoc gmComponentNameDoc smpDoc entrypoints)
|
||||||
, "Cabal components:\n" ++ render (nest 4 $
|
, "Cabal components:\n" ++ render (nest 4 $
|
||||||
|
@ -65,9 +65,9 @@ getGhcPkgProgram :: IOish m => GhcModT m FilePath
|
|||||||
getGhcPkgProgram = do
|
getGhcPkgProgram = do
|
||||||
crdl <- cradle
|
crdl <- cradle
|
||||||
progs <- optPrograms <$> options
|
progs <- optPrograms <$> options
|
||||||
case cradleProjectType crdl of
|
case cradleProject crdl of
|
||||||
StackProject -> do
|
(StackProject senv) -> do
|
||||||
Just ghcPkg <- getStackGhcPkgPath (cradleRootDir crdl)
|
Just ghcPkg <- getStackGhcPkgPath senv
|
||||||
return ghcPkg
|
return ghcPkg
|
||||||
_ ->
|
_ ->
|
||||||
return $ ghcPkgProgram progs
|
return $ ghcPkgProgram progs
|
||||||
@ -77,7 +77,7 @@ getPackageDbStack :: IOish m => GhcModT m [GhcPkgDb]
|
|||||||
getPackageDbStack = do
|
getPackageDbStack = do
|
||||||
crdl <- cradle
|
crdl <- cradle
|
||||||
mCusPkgStack <- getCustomPkgDbStack
|
mCusPkgStack <- getCustomPkgDbStack
|
||||||
stack <- case cradleProjectType crdl of
|
stack <- case cradleProject crdl of
|
||||||
PlainProject ->
|
PlainProject ->
|
||||||
return [GlobalDb, UserDb]
|
return [GlobalDb, UserDb]
|
||||||
SandboxProject -> do
|
SandboxProject -> do
|
||||||
@ -85,8 +85,8 @@ getPackageDbStack = do
|
|||||||
return $ [GlobalDb, db]
|
return $ [GlobalDb, db]
|
||||||
CabalProject ->
|
CabalProject ->
|
||||||
getCabalPackageDbStack
|
getCabalPackageDbStack
|
||||||
StackProject ->
|
(StackProject StackEnv {..}) ->
|
||||||
getStackPackageDbStack
|
return $ map PackageDb [seSnapshotPkgDb, seLocalPkgDb]
|
||||||
return $ fromMaybe stack mCusPkgStack
|
return $ fromMaybe stack mCusPkgStack
|
||||||
|
|
||||||
getPackageCachePaths :: IOish m => FilePath -> GhcModT m [FilePath]
|
getPackageCachePaths :: IOish m => FilePath -> GhcModT m [FilePath]
|
||||||
|
@ -27,6 +27,7 @@ import Control.Monad
|
|||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
import Control.Monad.Trans.Class
|
import Control.Monad.Trans.Class
|
||||||
import Data.List
|
import Data.List
|
||||||
|
import Data.List.Split
|
||||||
import Data.Char
|
import Data.Char
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Traversable hiding (mapM)
|
import Data.Traversable hiding (mapM)
|
||||||
@ -85,22 +86,29 @@ findStackConfigFile dir = do
|
|||||||
Just (d, Just a) -> return $ Just $ d </> a
|
Just (d, Just a) -> return $ Just $ d </> a
|
||||||
Just (_, Nothing) -> error "findStackConfigFile"
|
Just (_, Nothing) -> error "findStackConfigFile"
|
||||||
|
|
||||||
getStackDistDir :: (IOish m, GmOut m) => FilePath -> m (Maybe FilePath)
|
getStackEnv :: (IOish m, GmOut m) => FilePath -> m (Maybe StackEnv)
|
||||||
getStackDistDir projdir = U.withDirectory_ projdir $ runMaybeT $ do
|
getStackEnv projdir = U.withDirectory_ projdir $ runMaybeT $ do
|
||||||
takeWhile (/='\n') <$> readStack ["path", "--dist-dir"]
|
env <- map (liToTup . splitOn ": ") . lines <$> readStack ["path"]
|
||||||
|
let look k = fromJust $ lookup k env
|
||||||
|
return StackEnv {
|
||||||
|
seDistDir = look "dist-dir"
|
||||||
|
, seBinPath = splitSearchPath $ look "bin-path"
|
||||||
|
, seSnapshotPkgDb = look "snapshot-pkg-db"
|
||||||
|
, seLocalPkgDb = look "local-pkg-db"
|
||||||
|
}
|
||||||
|
where
|
||||||
|
liToTup [k,v] = (k,v)
|
||||||
|
liToTup _ = error "getStackEnv"
|
||||||
|
|
||||||
getStackGhcPath :: (IOish m, GmOut m) => FilePath -> m (Maybe FilePath)
|
getStackGhcPath :: IOish m => StackEnv -> m (Maybe FilePath)
|
||||||
getStackGhcPath = findExecutablesInStackBinPath "ghc"
|
getStackGhcPath = findExecutablesInStackBinPath "ghc"
|
||||||
|
|
||||||
getStackGhcPkgPath :: (IOish m, GmOut m) => FilePath -> m (Maybe FilePath)
|
getStackGhcPkgPath :: IOish m => StackEnv -> m (Maybe FilePath)
|
||||||
getStackGhcPkgPath = findExecutablesInStackBinPath "ghc-pkg"
|
getStackGhcPkgPath = findExecutablesInStackBinPath "ghc-pkg"
|
||||||
|
|
||||||
findExecutablesInStackBinPath :: (IOish m, GmOut m) => String -> FilePath -> m (Maybe FilePath)
|
findExecutablesInStackBinPath :: IOish m => String -> StackEnv -> m (Maybe FilePath)
|
||||||
findExecutablesInStackBinPath exe projdir =
|
findExecutablesInStackBinPath exe StackEnv {..} =
|
||||||
U.withDirectory_ projdir $ runMaybeT $ do
|
liftIO $ listToMaybe <$> findExecutablesInDirectories' seBinPath exe
|
||||||
path <- splitSearchPath . takeWhile (/='\n')
|
|
||||||
<$> readStack ["path", "--bin-path"]
|
|
||||||
MaybeT $ liftIO $ listToMaybe <$> findExecutablesInDirectories' path exe
|
|
||||||
|
|
||||||
findExecutablesInDirectories' :: [FilePath] -> String -> IO [FilePath]
|
findExecutablesInDirectories' :: [FilePath] -> String -> IO [FilePath]
|
||||||
findExecutablesInDirectories' path binary =
|
findExecutablesInDirectories' path binary =
|
||||||
|
@ -150,10 +150,10 @@ targetGhcOptions :: forall m. IOish m
|
|||||||
targetGhcOptions crdl sefnmn = do
|
targetGhcOptions crdl sefnmn = do
|
||||||
when (Set.null sefnmn) $ error "targetGhcOptions: no targets given"
|
when (Set.null sefnmn) $ error "targetGhcOptions: no targets given"
|
||||||
|
|
||||||
case cradleProjectType crdl of
|
case cradleProject crdl of
|
||||||
CabalProject -> cabalOpts crdl
|
proj
|
||||||
StackProject -> cabalOpts crdl
|
| isCabalHelperProject proj -> cabalOpts crdl
|
||||||
_ -> sandboxOpts crdl
|
| otherwise -> sandboxOpts crdl
|
||||||
where
|
where
|
||||||
zipMap f l = l `zip` (f `map` l)
|
zipMap f l = l `zip` (f `map` l)
|
||||||
|
|
||||||
@ -267,10 +267,10 @@ packageGhcOptions :: (Applicative m, IOish m, Gm m)
|
|||||||
=> m [GHCOption]
|
=> m [GHCOption]
|
||||||
packageGhcOptions = do
|
packageGhcOptions = do
|
||||||
crdl <- cradle
|
crdl <- cradle
|
||||||
case cradleProjectType crdl of
|
case cradleProject crdl of
|
||||||
CabalProject -> getGhcMergedPkgOptions
|
proj
|
||||||
StackProject -> getGhcMergedPkgOptions
|
| isCabalHelperProject proj -> getGhcMergedPkgOptions
|
||||||
_ -> sandboxOpts crdl
|
| otherwise -> sandboxOpts crdl
|
||||||
|
|
||||||
-- also works for plain projects!
|
-- also works for plain projects!
|
||||||
sandboxOpts :: (IOish m, GmEnv m) => Cradle -> m [String]
|
sandboxOpts :: (IOish m, GmEnv m) => Cradle -> m [String]
|
||||||
|
@ -139,12 +139,27 @@ defaultOptions = Options {
|
|||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
data ProjectType = CabalProject | SandboxProject | PlainProject | StackProject
|
data Project = CabalProject
|
||||||
deriving (Eq, Show)
|
| SandboxProject
|
||||||
|
| PlainProject
|
||||||
|
| StackProject StackEnv
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
isCabalHelperProject :: Project -> Bool
|
||||||
|
isCabalHelperProject StackProject {} = True
|
||||||
|
isCabalHelperProject CabalProject {} = True
|
||||||
|
isCabalHelperProject _ = False
|
||||||
|
|
||||||
|
data StackEnv = StackEnv {
|
||||||
|
seDistDir :: FilePath
|
||||||
|
, seBinPath :: [FilePath]
|
||||||
|
, seSnapshotPkgDb :: FilePath
|
||||||
|
, seLocalPkgDb :: FilePath
|
||||||
|
} deriving (Eq, Show)
|
||||||
|
|
||||||
-- | The environment where this library is used.
|
-- | The environment where this library is used.
|
||||||
data Cradle = Cradle {
|
data Cradle = Cradle {
|
||||||
cradleProjectType:: ProjectType
|
cradleProject :: Project
|
||||||
-- | The directory where this library is executed.
|
-- | The directory where this library is executed.
|
||||||
, cradleCurrentDir :: FilePath
|
, cradleCurrentDir :: FilePath
|
||||||
-- | The project root directory.
|
-- | The project root directory.
|
||||||
|
@ -679,7 +679,7 @@ nukeCaches = do
|
|||||||
chdir <- liftIO $ (</> "cabal-helper") <$> getAppUserDataDirectory "ghc-mod"
|
chdir <- liftIO $ (</> "cabal-helper") <$> getAppUserDataDirectory "ghc-mod"
|
||||||
c <- cradle
|
c <- cradle
|
||||||
|
|
||||||
when (cradleProjectType c == CabalProject || cradleProjectType c == StackProject) $ do
|
when (isCabalHelperProject $ cradleProject c) $ do
|
||||||
let root = cradleRootDir c
|
let root = cradleRootDir c
|
||||||
let dist = cradleDistDir c
|
let dist = cradleDistDir c
|
||||||
liftIO $ (trySome . removeDirectoryRecursive) `mapM_` [chdir, root </> dist]
|
liftIO $ (trySome . removeDirectoryRecursive) `mapM_` [chdir, root </> dist]
|
||||||
|
Loading…
Reference in New Issue
Block a user