1
1
{-# LANGUAGE CPP #-}
2
2
{-# LANGUAGE DeriveGeneric, DeriveFunctor, GeneralizedNewtypeDeriving,
3
- NamedFieldPuns, BangPatterns #-}
3
+ NamedFieldPuns, BangPatterns, ScopedTypeVariables #-}
4
4
{-# OPTIONS_GHC -fno-warn-orphans #-}
5
5
{-# LANGUAGE ScopedTypeVariables #-}
6
6
@@ -45,8 +45,10 @@ module Distribution.Client.FileMonitor (
45
45
46
46
import Prelude ()
47
47
import Distribution.Client.Compat.Prelude
48
+ import qualified Distribution.Compat.Binary as Binary
48
49
49
50
import qualified Data.Map.Strict as Map
51
+ import Data.Binary.Get (runGetOrFail )
50
52
import qualified Data.ByteString.Lazy as BS
51
53
import qualified Data.Hashable as Hashable
52
54
@@ -62,7 +64,7 @@ import Distribution.Compat.Time
62
64
import Distribution.Client.Glob
63
65
import Distribution.Simple.Utils (handleDoesNotExist , writeFileAtomic )
64
66
import Distribution.Client.Utils (mergeBy , MergeResult (.. ))
65
- import Distribution.Utils.Structured (structuredDecodeOrFailIO , structuredEncode )
67
+ import Distribution.Utils.Structured (structuredEncode , Tag ( .. ) )
66
68
import System.FilePath
67
69
import System.Directory
68
70
import System.IO
@@ -434,17 +436,19 @@ checkFileMonitorChanged
434
436
435
437
handleDoesNotExist (MonitorChanged MonitorFirstRun ) $
436
438
handleErrorCall (MonitorChanged MonitorCorruptCache ) $
437
- readCacheFile monitor
438
- >>= either (\ _ -> return (MonitorChanged MonitorCorruptCache ))
439
- checkStatusCache
439
+ withCacheFile monitor $
440
+ either (\ _ -> return (MonitorChanged MonitorCorruptCache ))
441
+ checkStatusCache
440
442
441
443
where
442
- checkStatusCache :: (MonitorStateFileSet , a , b ) -> IO (MonitorChanged a b )
444
+ checkStatusCache :: (MonitorStateFileSet , a , Either String b ) -> IO (MonitorChanged a b )
443
445
checkStatusCache (cachedFileStatus, cachedKey, cachedResult) = do
444
446
change <- checkForChanges
445
447
case change of
446
448
Just reason -> return (MonitorChanged reason)
447
- Nothing -> return (MonitorUnchanged cachedResult monitorFiles)
449
+ Nothing -> case cachedResult of
450
+ Left _ -> pure (MonitorChanged MonitorCorruptCache )
451
+ Right cr -> return (MonitorUnchanged cr monitorFiles)
448
452
where monitorFiles = reconstructMonitorFilePaths cachedFileStatus
449
453
where
450
454
-- In fileMonitorCheckIfOnlyValueChanged mode we want to guarantee that
@@ -479,7 +483,7 @@ checkFileMonitorChanged
479
483
= return Nothing
480
484
481
485
-- Check if any file has changed
482
- checkFileChange :: MonitorStateFileSet -> a -> b -> IO (Maybe (MonitorChangedReason a ))
486
+ checkFileChange :: MonitorStateFileSet -> a -> Either String b -> IO (Maybe (MonitorChangedReason a ))
483
487
checkFileChange cachedFileStatus cachedKey cachedResult = do
484
488
res <- probeFileSystem root cachedFileStatus
485
489
case res of
@@ -492,21 +496,50 @@ checkFileMonitorChanged
492
496
493
497
-- But we might still want to update the cache
494
498
whenCacheChanged cacheStatus $
495
- rewriteCacheFile monitor cachedFileStatus' cachedKey cachedResult
499
+ case cachedResult of
500
+ Left _ -> pure ()
501
+ Right cr -> rewriteCacheFile monitor cachedFileStatus' cachedKey cr
496
502
497
503
return Nothing
498
504
505
+ -- | Lazily decode a triple, parsing the first two fields strictly and
506
+ -- returning a lazy value containing either the last one or an error.
507
+ -- This is helpful for cabal cache files where the first two components
508
+ -- contain header data that lets one test if the cache is still valid,
509
+ -- and the last (potentially large) component is the cached value itself.
510
+ -- This way we can test for cache validity without needing to pay the
511
+ -- cost of the decode of stale cache data. This lives here rather than
512
+ -- Distribution.Utils.Structured because it depends on a newer version of
513
+ -- binary than supported in the Cabal library proper.
514
+ structuredDecodeTriple
515
+ :: forall a b c . (Structured a , Structured b , Structured c , Binary. Binary a , Binary. Binary b , Binary. Binary c )
516
+ => BS. ByteString -> Either String (a , b , Either String c )
517
+ structuredDecodeTriple lbs =
518
+ let partialDecode =
519
+ (`runGetOrFail` lbs) $ do
520
+ (_ :: Tag (a ,b ,c )) <- Binary. get
521
+ (a :: a ) <- Binary. get
522
+ (b :: b ) <- Binary. get
523
+ pure (a, b)
524
+ cleanEither (Left (_, pos, msg)) = Left (" Data.Binary.Get.runGet at position " ++ show pos ++ " : " ++ msg)
525
+ cleanEither (Right (_,_,v)) = Right v
526
+
527
+ in case partialDecode of
528
+ Left (_, pos, msg) -> Left (" Data.Binary.Get.runGet at position " ++ show pos ++ " : " ++ msg)
529
+ Right (lbs', _, (x,y)) -> Right (x, y, cleanEither $ runGetOrFail (Binary. get :: Binary. Get c ) lbs')
530
+
499
531
-- | Helper for reading the cache file.
500
532
--
501
533
-- This determines the type and format of the binary cache file.
502
534
--
503
- readCacheFile :: (Binary a , Structured a , Binary b , Structured b )
535
+ withCacheFile :: (Binary a , Structured a , Binary b , Structured b )
504
536
=> FileMonitor a b
505
- -> IO (Either String (MonitorStateFileSet , a , b ))
506
- readCacheFile FileMonitor {fileMonitorCacheFile} =
537
+ -> (Either String (MonitorStateFileSet , a , Either String b ) -> IO r )
538
+ -> IO r
539
+ withCacheFile (FileMonitor {fileMonitorCacheFile}) k =
507
540
withBinaryFile fileMonitorCacheFile ReadMode $ \ hnd -> do
508
- contents <- BS. hGetContents hnd
509
- structuredDecodeOrFailIO contents
541
+ contents <- structuredDecodeTriple <$> BS. hGetContents hnd
542
+ k contents
510
543
511
544
-- | Helper for writing the cache file.
512
545
--
@@ -989,8 +1022,8 @@ readCacheFileHashes :: (Binary a, Structured a, Binary b, Structured b)
989
1022
=> FileMonitor a b -> IO FileHashCache
990
1023
readCacheFileHashes monitor =
991
1024
handleDoesNotExist Map. empty $
992
- handleErrorCall Map. empty $ do
993
- res <- readCacheFile monitor
1025
+ handleErrorCall Map. empty $
1026
+ withCacheFile monitor $ \ res ->
994
1027
case res of
995
1028
Left _ -> return Map. empty
996
1029
Right (msfs, _, _) -> return (mkFileHashCache msfs)
@@ -1136,4 +1169,3 @@ handleIOException e =
1136
1169
------------------------------------------------------------------------------
1137
1170
-- Instances
1138
1171
--
1139
-
0 commit comments