Skip to content

Commit 7a215d2

Browse files
authored
Infrastructure for on-disk incremental builds (#189)
This is intended for the DAML CLI compiler which is also built upon `ghcide`. For now, we have no intention of using this in the DAML IDE or in ghcide but that might change in the future.
1 parent 981cd8b commit 7a215d2

File tree

9 files changed

+159
-24
lines changed

9 files changed

+159
-24
lines changed

src/Development/IDE/Core/Compile.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module Development.IDE.Core.Compile
1414
, typecheckModule
1515
, computePackageDeps
1616
, addRelativeImport
17+
, mkTcModuleResult
1718
) where
1819

1920
import Development.IDE.Core.RuleTypes

src/Development/IDE/Core/FileStore.hs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ module Development.IDE.Core.FileStore(
1111
VFSHandle,
1212
makeVFSHandle,
1313
makeLSPVFSHandle,
14+
getSourceFingerprint
1415
) where
1516

17+
import Foreign.Ptr
18+
import Foreign.ForeignPtr
19+
import Fingerprint
1620
import StringBuffer
1721
import Development.IDE.GHC.Orphans()
1822
import Development.IDE.GHC.Util
@@ -41,7 +45,6 @@ import Data.Time
4145
import Foreign.C.String
4246
import Foreign.C.Types
4347
import Foreign.Marshal (alloca)
44-
import Foreign.Ptr
4548
import Foreign.Storable
4649
import qualified System.Posix.Error as Posix
4750
#endif
@@ -89,17 +92,34 @@ type instance RuleResult GetFileContents = (FileVersion, Maybe StringBuffer)
8992
-- | Does the file exist.
9093
type instance RuleResult GetFileExists = Bool
9194

95+
type instance RuleResult FingerprintSource = Fingerprint
9296

9397
data GetFileExists = GetFileExists
9498
deriving (Eq, Show, Generic)
9599
instance Hashable GetFileExists
96100
instance NFData GetFileExists
101+
instance Binary GetFileExists
97102

98103
data GetFileContents = GetFileContents
99104
deriving (Eq, Show, Generic)
100105
instance Hashable GetFileContents
101106
instance NFData GetFileContents
107+
instance Binary GetFileContents
102108

109+
data FingerprintSource = FingerprintSource
110+
deriving (Eq, Show, Generic)
111+
instance Hashable FingerprintSource
112+
instance NFData FingerprintSource
113+
instance Binary FingerprintSource
114+
115+
fingerprintSourceRule :: Rules ()
116+
fingerprintSourceRule =
117+
define $ \FingerprintSource file -> do
118+
(_, mbContent) <- getFileContents file
119+
content <- liftIO $ maybe (hGetStringBuffer $ fromNormalizedFilePath file) pure mbContent
120+
fingerprint <- liftIO $ fpStringBuffer content
121+
pure ([], Just fingerprint)
122+
where fpStringBuffer (StringBuffer buf len cur) = withForeignPtr buf $ \ptr -> fingerprintData (ptr `plusPtr` cur) len
103123

104124
getFileExistsRule :: VFSHandle -> Rules ()
105125
getFileExistsRule vfs =
@@ -152,6 +172,9 @@ getModificationTimeRule vfs =
152172
foreign import ccall "getmodtime" c_getModTime :: CString -> Ptr CTime -> Ptr CLong -> IO Int
153173
#endif
154174

175+
getSourceFingerprint :: NormalizedFilePath -> Action Fingerprint
176+
getSourceFingerprint = use_ FingerprintSource
177+
155178
getFileContentsRule :: VFSHandle -> Rules ()
156179
getFileContentsRule vfs =
157180
define $ \GetFileContents file -> do
@@ -188,6 +211,7 @@ fileStoreRules vfs = do
188211
getModificationTimeRule vfs
189212
getFileContentsRule vfs
190213
getFileExistsRule vfs
214+
fingerprintSourceRule
191215

192216

193217
-- | Notify the compiler service that a particular file has been modified.

src/Development/IDE/Core/OfInterest.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module Development.IDE.Core.OfInterest(
1414
) where
1515

1616
import Control.Concurrent.Extra
17+
import Data.Binary
1718
import Data.Hashable
1819
import Control.DeepSeq
1920
import GHC.Generics
@@ -44,6 +45,7 @@ data GetFilesOfInterest = GetFilesOfInterest
4445
deriving (Eq, Show, Typeable, Generic)
4546
instance Hashable GetFilesOfInterest
4647
instance NFData GetFilesOfInterest
48+
instance Binary GetFilesOfInterest
4749

4850

4951
ofInterestRules :: Rules ()

src/Development/IDE/Core/RuleTypes.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module Development.IDE.Core.RuleTypes(
1212
) where
1313

1414
import Control.DeepSeq
15+
import Data.Binary
1516
import Development.IDE.Import.DependencyInformation
1617
import Development.IDE.GHC.Util
1718
import Development.IDE.Types.Location
@@ -86,50 +87,60 @@ data GetParsedModule = GetParsedModule
8687
deriving (Eq, Show, Typeable, Generic)
8788
instance Hashable GetParsedModule
8889
instance NFData GetParsedModule
90+
instance Binary GetParsedModule
8991

9092
data GetLocatedImports = GetLocatedImports
9193
deriving (Eq, Show, Typeable, Generic)
9294
instance Hashable GetLocatedImports
9395
instance NFData GetLocatedImports
96+
instance Binary GetLocatedImports
9497

9598
data GetDependencyInformation = GetDependencyInformation
9699
deriving (Eq, Show, Typeable, Generic)
97100
instance Hashable GetDependencyInformation
98101
instance NFData GetDependencyInformation
102+
instance Binary GetDependencyInformation
99103

100104
data ReportImportCycles = ReportImportCycles
101105
deriving (Eq, Show, Typeable, Generic)
102106
instance Hashable ReportImportCycles
103107
instance NFData ReportImportCycles
108+
instance Binary ReportImportCycles
104109

105110
data GetDependencies = GetDependencies
106111
deriving (Eq, Show, Typeable, Generic)
107112
instance Hashable GetDependencies
108113
instance NFData GetDependencies
114+
instance Binary GetDependencies
109115

110116
data TypeCheck = TypeCheck
111117
deriving (Eq, Show, Typeable, Generic)
112118
instance Hashable TypeCheck
113119
instance NFData TypeCheck
120+
instance Binary TypeCheck
114121

115122
data GetSpanInfo = GetSpanInfo
116123
deriving (Eq, Show, Typeable, Generic)
117124
instance Hashable GetSpanInfo
118125
instance NFData GetSpanInfo
126+
instance Binary GetSpanInfo
119127

120128
data GenerateCore = GenerateCore
121129
deriving (Eq, Show, Typeable, Generic)
122130
instance Hashable GenerateCore
123131
instance NFData GenerateCore
132+
instance Binary GenerateCore
124133

125134
data GhcSession = GhcSession
126135
deriving (Eq, Show, Typeable, Generic)
127136
instance Hashable GhcSession
128137
instance NFData GhcSession
138+
instance Binary GhcSession
129139

130140
-- Note that we embed the filepath here instead of using the filepath associated with Shake keys.
131141
-- Otherwise we will garbage collect the result since files in package dependencies will not be declared reachable.
132142
data GetHieFile = GetHieFile FilePath
133143
deriving (Eq, Show, Typeable, Generic)
134144
instance Hashable GetHieFile
135145
instance NFData GetHieFile
146+
instance Binary GetHieFile

src/Development/IDE/Core/Rules.hs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ module Development.IDE.Core.Rules(
2626
generateCore,
2727
) where
2828

29+
import Fingerprint
30+
31+
import Data.Binary
2932
import Control.Monad
3033
import Control.Monad.Trans.Class
3134
import Control.Monad.Trans.Maybe
@@ -141,11 +144,13 @@ priorityFilesOfInterest = Priority (-2)
141144

142145
getParsedModuleRule :: Rules ()
143146
getParsedModuleRule =
144-
define $ \GetParsedModule file -> do
147+
defineEarlyCutoff $ \GetParsedModule file -> do
145148
(_, contents) <- getFileContents file
146149
packageState <- hscEnv <$> use_ GhcSession file
147150
opt <- getIdeOptions
148-
liftIO $ parseModule opt packageState (fromNormalizedFilePath file) contents
151+
r <- liftIO $ parseModule opt packageState (fromNormalizedFilePath file) contents
152+
mbFingerprint <- traverse (const $ getSourceFingerprint file) (optShakeFiles opt)
153+
pure (fingerprintToBS <$> mbFingerprint, r)
149154

150155
getLocatedImportsRule :: Rules ()
151156
getLocatedImportsRule =
@@ -252,11 +257,13 @@ reportImportCyclesRule =
252257
-- NOTE: result does not include the argument file.
253258
getDependenciesRule :: Rules ()
254259
getDependenciesRule =
255-
define $ \GetDependencies file -> do
260+
defineEarlyCutoff $ \GetDependencies file -> do
256261
depInfo@DependencyInformation{..} <- use_ GetDependencyInformation file
257262
let allFiles = reachableModules depInfo
258263
_ <- uses_ ReportImportCycles allFiles
259-
return ([], transitiveDeps depInfo file)
264+
opts <- getIdeOptions
265+
let mbFingerprints = map (fingerprintString . fromNormalizedFilePath) allFiles <$ optShakeFiles opts
266+
return (fingerprintToBS . fingerprintFingerprints <$> mbFingerprints, ([], transitiveDeps depInfo file))
260267

261268
-- Source SpanInfo is used by AtPoint and Goto Definition.
262269
getSpanInfoRule :: Rules ()
@@ -301,6 +308,7 @@ type instance RuleResult GhcSessionIO = GhcSessionFun
301308
data GhcSessionIO = GhcSessionIO deriving (Eq, Show, Typeable, Generic)
302309
instance Hashable GhcSessionIO
303310
instance NFData GhcSessionIO
311+
instance Binary GhcSessionIO
304312

305313
newtype GhcSessionFun = GhcSessionFun (FilePath -> Action HscEnvEq)
306314
instance Show GhcSessionFun where show _ = "GhcSessionFun"
@@ -312,10 +320,11 @@ loadGhcSession = do
312320
defineNoFile $ \GhcSessionIO -> do
313321
opts <- getIdeOptions
314322
liftIO $ GhcSessionFun <$> optGhcSession opts
315-
define $ \GhcSession file -> do
323+
defineEarlyCutoff $ \GhcSession file -> do
316324
GhcSessionFun fun <- useNoFile_ GhcSessionIO
317325
val <- fun $ fromNormalizedFilePath file
318-
return ([], Just val)
326+
opts <- getIdeOptions
327+
return ("" <$ optShakeFiles opts, ([], Just val))
319328

320329

321330
getHieFileRule :: Rules ()

src/Development/IDE/Core/Service.hs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module Development.IDE.Core.Service(
2020

2121
import Control.Concurrent.Extra
2222
import Control.Concurrent.Async
23+
import Data.Maybe
2324
import Development.IDE.Types.Options (IdeOptions(..))
2425
import Control.Monad
2526
import Development.IDE.Core.FileStore
@@ -55,9 +56,10 @@ initialise mainRule getLspId toDiags logger options vfs =
5556
logger
5657
(optShakeProfiling options)
5758
(optReportProgress options)
58-
(shakeOptions { shakeThreads = optThreads options
59-
, shakeFiles = "/dev/null"
60-
}) $ do
59+
shakeOptions
60+
{ shakeThreads = optThreads options
61+
, shakeFiles = fromMaybe "/dev/null" (optShakeFiles options)
62+
} $ do
6163
addIdeGlobal $ GlobalIdeOptions options
6264
fileStoreRules vfs
6365
ofInterestRules

0 commit comments

Comments
 (0)