Use stdout pipe instead of temp.files in Find

This commit is contained in:
Nikolay Yakimov 2016-01-05 13:38:25 +03:00
parent 306cb939a9
commit da1c1bebb2
5 changed files with 41 additions and 74 deletions

View File

@ -1,4 +1,4 @@
{-# LANGUAGE CPP, BangPatterns, DoAndIfThenElse #-} {-# LANGUAGE CPP, BangPatterns #-}
module Language.Haskell.GhcMod.Find module Language.Haskell.GhcMod.Find
#ifndef SPEC #ifndef SPEC
@ -22,7 +22,6 @@ import Language.Haskell.GhcMod.Convert
import Language.Haskell.GhcMod.Gap import Language.Haskell.GhcMod.Gap
import Language.Haskell.GhcMod.Monad import Language.Haskell.GhcMod.Monad
import Language.Haskell.GhcMod.Output import Language.Haskell.GhcMod.Output
import Language.Haskell.GhcMod.PathsAndFiles
import Language.Haskell.GhcMod.Types import Language.Haskell.GhcMod.Types
import Language.Haskell.GhcMod.Utils import Language.Haskell.GhcMod.Utils
import Language.Haskell.GhcMod.World import Language.Haskell.GhcMod.World
@ -32,6 +31,7 @@ import Name
import Module import Module
import Exception import Exception
import Control.Arrow
import Control.Applicative import Control.Applicative
import Control.Monad import Control.Monad
import Control.Monad.Trans.Control import Control.Monad.Trans.Control
@ -40,10 +40,7 @@ import Data.Function
import Data.List import Data.List
import Data.Map (Map) import Data.Map (Map)
import qualified Data.Map as M import qualified Data.Map as M
import System.Directory
import System.Directory.ModTime import System.Directory.ModTime
import System.FilePath ((</>))
import System.IO
import Prelude import Prelude
---------------------------------------------------------------- ----------------------------------------------------------------
@ -53,21 +50,19 @@ type Symbol = String
-- | Database from 'Symbol' to \['ModuleString'\]. -- | Database from 'Symbol' to \['ModuleString'\].
data SymbolDb = SymbolDb data SymbolDb = SymbolDb
{ table :: Map Symbol [ModuleString] { table :: Map Symbol [ModuleString]
, symbolDbCachePath :: FilePath , timestamp :: ModTime
} deriving (Show) } deriving (Show, Read)
isOutdated :: IOish m => SymbolDb -> GhcModT m Bool isOutdated :: IOish m => SymbolDb -> GhcModT m Bool
isOutdated db = isOutdated db =
(liftIO . isOlderThan (symbolDbCachePath db)) =<< timedPackageCaches isOlderThan (timestamp db) <$> timedPackageCaches
---------------------------------------------------------------- ----------------------------------------------------------------
-- | Looking up 'SymbolDb' with 'Symbol' to \['ModuleString'\] -- | Looking up 'SymbolDb' with 'Symbol' to \['ModuleString'\]
-- which will be concatenated. 'loadSymbolDb' is called internally. -- which will be concatenated. 'loadSymbolDb' is called internally.
findSymbol :: IOish m => Symbol -> GhcModT m String findSymbol :: IOish m => Symbol -> GhcModT m String
findSymbol sym = do findSymbol sym = loadSymbolDb >>= lookupSymbol sym
tmpdir <- cradleTempDir <$> cradle
loadSymbolDb tmpdir >>= lookupSymbol sym
-- | Looking up 'SymbolDb' with 'Symbol' to \['ModuleString'\] -- | Looking up 'SymbolDb' with 'Symbol' to \['ModuleString'\]
-- which will be concatenated. -- which will be concatenated.
@ -80,57 +75,33 @@ lookupSym sym db = M.findWithDefault [] sym $ table db
--------------------------------------------------------------- ---------------------------------------------------------------
-- | Loading a file and creates 'SymbolDb'. -- | Loading a file and creates 'SymbolDb'.
loadSymbolDb :: IOish m => FilePath -> GhcModT m SymbolDb loadSymbolDb :: IOish m => GhcModT m SymbolDb
loadSymbolDb dir = do loadSymbolDb = do
ghcMod <- liftIO ghcModExecutable ghcMod <- liftIO ghcModExecutable
readProc <- gmReadProcess readProc <- gmReadProcess
file <- liftIO $ chop <$> readProc ghcMod ["dumpsym", dir] "" (!db, !ts) <- first M.fromAscList . read <$> liftIO
!db <- M.fromAscList . map conv . lines <$> liftIO (readFile file) (readProc ghcMod ["--verbose", "error", "dumpsym"] "")
return $ SymbolDb return SymbolDb {
{ table = db table = db
, symbolDbCachePath = file , timestamp = ts
} }
where
conv :: String -> (Symbol, [ModuleString])
conv = read
chop :: String -> String
chop "" = ""
chop xs = init xs
---------------------------------------------------------------- ----------------------------------------------------------------
-- used 'ghc-mod dumpsym' -- used 'ghc-mod dumpsym'
-- | Dumping a set of ('Symbol',\['ModuleString'\]) to a file -- | Dumps a tuple of
-- if the file does not exist or is invalid. -- (\[('Symbol',\['ModuleString'\])\], 'ModTime') to stdout
-- The file name is printed. dumpSymbol :: IOish m => GhcModT m String
dumpSymbol = do
dumpSymbol :: IOish m => FilePath -> GhcModT m String timestamp <- liftIO getCurrentModTime
dumpSymbol dir = do st <- runGmPkgGhc getGlobalSymbolTable
create <- (liftIO . isOlderThan cache) =<< timedPackageCaches return . show $ (st, timestamp)
runGmPkgGhc $ do
when create $
liftIO . writeSymbolCache cache =<< getGlobalSymbolTable
return $ unlines [cache]
where
cache = dir </> symbolCacheFile
writeSymbolCache :: FilePath
-> [(Symbol, [ModuleString])]
-> IO ()
writeSymbolCache cache sm =
void . withFile cache WriteMode $ \hdl ->
mapM (hPrint hdl) sm
-- | Check whether given file is older than any file from the given set. -- | Check whether given file is older than any file from the given set.
-- Returns True if given file does not exist. -- Returns True if given file does not exist.
isOlderThan :: FilePath -> [TimedFile] -> IO Bool isOlderThan :: ModTime -> [TimedFile] -> Bool
isOlderThan cache files = do isOlderThan tCache files =
exist <- doesFileExist cache any (tCache <=) $ map tfTime files -- including equal just in case
if not exist
then return True
else do
tCache <- getModTime cache
return $ any (tCache <=) $ map tfTime files -- including equal just in case
-- | Browsing all functions in all system modules. -- | Browsing all functions in all system modules.
getGlobalSymbolTable :: LightGhc [(Symbol, [ModuleString])] getGlobalSymbolTable :: LightGhc [(Symbol, [ModuleString])]
@ -158,30 +129,29 @@ collectModules = map tieup . groupBy ((==) `on` fst) . sort
---------------------------------------------------------------- ----------------------------------------------------------------
data AsyncSymbolDb = AsyncSymbolDb FilePath (MVar (Either SomeException SymbolDb)) data AsyncSymbolDb = AsyncSymbolDb (MVar (Either SomeException SymbolDb))
asyncLoadSymbolDb :: IOish m asyncLoadSymbolDb :: IOish m
=> FilePath => MVar (Either SomeException SymbolDb)
-> MVar (Either SomeException SymbolDb)
-> GhcModT m () -> GhcModT m ()
asyncLoadSymbolDb tmpdir mv = void $ asyncLoadSymbolDb mv = void $
liftBaseWith $ \run -> forkIO $ void $ run $ do liftBaseWith $ \run -> forkIO $ void $ run $ do
edb <- gtry $ loadSymbolDb tmpdir edb <- gtry loadSymbolDb
liftIO $ putMVar mv edb liftIO $ putMVar mv edb
newAsyncSymbolDb :: IOish m => FilePath -> GhcModT m AsyncSymbolDb newAsyncSymbolDb :: IOish m => GhcModT m AsyncSymbolDb
newAsyncSymbolDb tmpdir = do newAsyncSymbolDb = do
mv <- liftIO newEmptyMVar mv <- liftIO newEmptyMVar
asyncLoadSymbolDb tmpdir mv asyncLoadSymbolDb mv
return $ AsyncSymbolDb tmpdir mv return $ AsyncSymbolDb mv
getAsyncSymbolDb :: forall m. IOish m => AsyncSymbolDb -> GhcModT m SymbolDb getAsyncSymbolDb :: forall m. IOish m => AsyncSymbolDb -> GhcModT m SymbolDb
getAsyncSymbolDb (AsyncSymbolDb tmpdir mv) = do getAsyncSymbolDb (AsyncSymbolDb mv) = do
db <- liftIO $ handleEx <$> takeMVar mv db <- liftIO $ handleEx <$> takeMVar mv
outdated <- isOutdated db outdated <- isOutdated db
if outdated if outdated
then do then do
asyncLoadSymbolDb tmpdir mv asyncLoadSymbolDb mv
liftIO $ handleEx <$> readMVar mv liftIO $ handleEx <$> readMVar mv
else do else do
liftIO $ putMVar mv $ Right db liftIO $ putMVar mv $ Right db

View File

@ -29,7 +29,7 @@ import Prelude
#if MIN_VERSION_directory(1,2,0) #if MIN_VERSION_directory(1,2,0)
newtype ModTime = ModTime UTCTime newtype ModTime = ModTime UTCTime
deriving (Eq, Ord) deriving (Eq, Ord, Show, Read)
getCurrentModTime = ModTime <$> getCurrentTime getCurrentModTime = ModTime <$> getCurrentTime
instance Binary ModTime where instance Binary ModTime where
@ -41,7 +41,7 @@ instance Binary ModTime where
#else #else
newtype ModTime = ModTime ClockTime newtype ModTime = ModTime ClockTime
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show, Read)
getCurrentModTime = ModTime <$> getClockTime getCurrentModTime = ModTime <$> getClockTime
instance Binary ModTime where instance Binary ModTime where

View File

@ -49,8 +49,7 @@ progMain (globalOptions, commands) = runGmOutT globalOptions $
legacyInteractive :: IOish m => GhcModT m () legacyInteractive :: IOish m => GhcModT m ()
legacyInteractive = do legacyInteractive = do
prepareCabalHelper prepareCabalHelper
tmpdir <- cradleTempDir <$> cradle asyncSymbolDb <- newAsyncSymbolDb
asyncSymbolDb <- newAsyncSymbolDb tmpdir
world <- getCurrentWorld world <- getCurrentWorld
legacyInteractiveLoop asyncSymbolDb world legacyInteractiveLoop asyncSymbolDb world
@ -137,7 +136,7 @@ ghcCommands (CmdBoot) = boot
-- ghcCommands (CmdRoot) = undefined -- handled in wrapGhcCommands -- ghcCommands (CmdRoot) = undefined -- handled in wrapGhcCommands
ghcCommands (CmdLegacyInteractive) = legacyInteractive >> return "" ghcCommands (CmdLegacyInteractive) = legacyInteractive >> return ""
ghcCommands (CmdModules detail) = modules detail ghcCommands (CmdModules detail) = modules detail
ghcCommands (CmdDumpSym tmpdir) = dumpSymbol tmpdir ghcCommands (CmdDumpSym) = dumpSymbol
ghcCommands (CmdFind symb) = findSymbol symb ghcCommands (CmdFind symb) = findSymbol symb
ghcCommands (CmdDoc m) = pkgDoc m ghcCommands (CmdDoc m) = pkgDoc m
ghcCommands (CmdLint opts file) = lint opts file ghcCommands (CmdLint opts file) = lint opts file

View File

@ -42,7 +42,7 @@ data GhcModCommands =
| CmdRoot | CmdRoot
| CmdLegacyInteractive | CmdLegacyInteractive
| CmdModules Bool | CmdModules Bool
| CmdDumpSym FilePath | CmdDumpSym
| CmdFind Symbol | CmdFind Symbol
| CmdDoc Module | CmdDoc Module
| CmdLint LintOpts FilePath | CmdLint LintOpts FilePath
@ -110,7 +110,7 @@ commands =
$$ info modulesArgSpec $$ info modulesArgSpec
$$ progDesc "List all visible modules" $$ progDesc "List all visible modules"
<> command "dumpsym" <> command "dumpsym"
$$ info dumpSymArgSpec idm $$ info (pure CmdDumpSym) idm
<> command "find" <> command "find"
$$ info findArgSpec $$ info findArgSpec
$$ progDesc "List all modules that define SYMBOL" $$ progDesc "List all modules that define SYMBOL"
@ -226,7 +226,7 @@ locArgSpec x = x
<*> argument int (metavar "COL") <*> argument int (metavar "COL")
) )
modulesArgSpec, dumpSymArgSpec, docArgSpec, findArgSpec, modulesArgSpec, docArgSpec, findArgSpec,
lintArgSpec, browseArgSpec, checkArgSpec, expandArgSpec, lintArgSpec, browseArgSpec, checkArgSpec, expandArgSpec,
infoArgSpec, typeArgSpec, autoArgSpec, splitArgSpec, infoArgSpec, typeArgSpec, autoArgSpec, splitArgSpec,
sigArgSpec, refineArgSpec, debugComponentArgSpec, sigArgSpec, refineArgSpec, debugComponentArgSpec,
@ -237,7 +237,6 @@ modulesArgSpec = CmdModules
$$ long "detailed" $$ long "detailed"
<=> short 'd' <=> short 'd'
<=> help "Print package modules belong to" <=> help "Print package modules belong to"
dumpSymArgSpec = CmdDumpSym <$> strArg "TMPDIR"
findArgSpec = CmdFind <$> strArg "SYMBOL" findArgSpec = CmdFind <$> strArg "SYMBOL"
docArgSpec = CmdDoc <$> strArg "MODULE" docArgSpec = CmdDoc <$> strArg "MODULE"
lintArgSpec = CmdLint lintArgSpec = CmdLint

View File

@ -1,7 +1,6 @@
module FindSpec where module FindSpec where
import Language.Haskell.GhcMod.Find import Language.Haskell.GhcMod.Find
import Control.Monad
import Test.Hspec import Test.Hspec
import TestUtils import TestUtils
@ -9,5 +8,5 @@ spec :: Spec
spec = do spec = do
describe "db <- loadSymbolDb" $ do describe "db <- loadSymbolDb" $ do
it "lookupSymbol' db \"head\" contains at least `Data.List'" $ do it "lookupSymbol' db \"head\" contains at least `Data.List'" $ do
db <- runD $ loadSymbolDb =<< (cradleTempDir `liftM` cradle) db <- runD $ loadSymbolDb
lookupSym "head" db `shouldContain` [ModuleString "Data.List"] lookupSym "head" db `shouldContain` [ModuleString "Data.List"]