| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Distribution.Client.FileMonitor
Description
An abstraction to help with re-running actions when files or other input values they depend on have changed.
Synopsis
- monitorDirectory :: FilePath -> MonitorFilePath
- monitorDirectoryExistence :: FilePath -> MonitorFilePath
- monitorFile :: FilePath -> MonitorFilePath
- monitorFileExistence :: FilePath -> MonitorFilePath
- monitorFileGlob :: RootedGlob -> MonitorFilePath
- monitorFileGlobExistence :: RootedGlob -> MonitorFilePath
- monitorFileHashed :: FilePath -> MonitorFilePath
- monitorFileHashedSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath]
- monitorFileOrDirectory :: FilePath -> MonitorFilePath
- monitorFileSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath]
- monitorNonExistentDirectory :: FilePath -> MonitorFilePath
- monitorNonExistentFile :: FilePath -> MonitorFilePath
- data FilePathRoot
- data MonitorFilePath
- data MonitorKindDir
- data MonitorKindFile
- data RootedGlob = RootedGlob FilePathRoot Glob
- data Glob
- data FileMonitor a b = FileMonitor {}
- newFileMonitor :: Eq a => FilePath -> FileMonitor a b
- data MonitorChanged a b
- data MonitorChangedReason a
- checkFileMonitorChanged :: (Binary a, Structured a, Binary b, Structured b) => FileMonitor a b -> FilePath -> a -> IO (MonitorChanged a b)
- updateFileMonitor :: (Binary a, Structured a, Binary b, Structured b) => FileMonitor a b -> FilePath -> Maybe MonitorTimestamp -> [MonitorFilePath] -> a -> b -> IO ()
- data MonitorTimestamp
- beginUpdateFileMonitor :: IO MonitorTimestamp
- data MonitorStateFileSet
- data MonitorStateFile
- data MonitorStateGlob
Declaring files to monitor
monitorFile :: FilePath -> MonitorFilePath #
monitorFileHashedSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath] #
monitorFileSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath] #
data FilePathRoot #
Constructors
| FilePathRelative | |
| FilePathRoot FilePath | |
| FilePathHomeDir |
Instances
| Parsec FilePathRoot # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods parsec :: CabalParsing m => m FilePathRoot # | |||||
| Pretty FilePathRoot # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| Structured FilePathRoot # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| Binary FilePathRoot # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| Generic FilePathRoot # | |||||
Defined in Distribution.Simple.FileMonitor.Types Associated Types
| |||||
| Show FilePathRoot # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods showsPrec :: Int -> FilePathRoot -> ShowS # show :: FilePathRoot -> String # showList :: [FilePathRoot] -> ShowS # | |||||
| Eq FilePathRoot # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| type Rep FilePathRoot # | |||||
Defined in Distribution.Simple.FileMonitor.Types type Rep FilePathRoot = D1 ('MetaData "FilePathRoot" "Distribution.Simple.FileMonitor.Types" "Cabal-3.14.1.0-1c71" 'False) (C1 ('MetaCons "FilePathRelative" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "FilePathRoot" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 FilePath)) :+: C1 ('MetaCons "FilePathHomeDir" 'PrefixI 'False) (U1 :: Type -> Type))) | |||||
data MonitorFilePath #
Constructors
| MonitorFile | |
Fields | |
| MonitorFileGlob | |
Fields | |
Instances
| Structured MonitorFilePath # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| Binary MonitorFilePath # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods put :: MonitorFilePath -> Put # get :: Get MonitorFilePath # putList :: [MonitorFilePath] -> Put # | |||||
| Generic MonitorFilePath # | |||||
Defined in Distribution.Simple.FileMonitor.Types Associated Types
Methods from :: MonitorFilePath -> Rep MonitorFilePath x to :: Rep MonitorFilePath x -> MonitorFilePath | |||||
| Show MonitorFilePath # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods showsPrec :: Int -> MonitorFilePath -> ShowS # show :: MonitorFilePath -> String # showList :: [MonitorFilePath] -> ShowS # | |||||
| Eq MonitorFilePath # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods (==) :: MonitorFilePath -> MonitorFilePath -> Bool # (/=) :: MonitorFilePath -> MonitorFilePath -> Bool # | |||||
| type Rep MonitorFilePath # | |||||
Defined in Distribution.Simple.FileMonitor.Types type Rep MonitorFilePath = D1 ('MetaData "MonitorFilePath" "Distribution.Simple.FileMonitor.Types" "Cabal-3.14.1.0-1c71" 'False) (C1 ('MetaCons "MonitorFile" 'PrefixI 'True) (S1 ('MetaSel ('Just "monitorKindFile") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 MonitorKindFile) :*: (S1 ('MetaSel ('Just "monitorKindDir") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 MonitorKindDir) :*: S1 ('MetaSel ('Just "monitorPath") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 FilePath))) :+: C1 ('MetaCons "MonitorFileGlob" 'PrefixI 'True) (S1 ('MetaSel ('Just "monitorKindFile") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 MonitorKindFile) :*: (S1 ('MetaSel ('Just "monitorKindDir") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 MonitorKindDir) :*: S1 ('MetaSel ('Just "monitorPathGlob") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 RootedGlob)))) | |||||
data MonitorKindDir #
Constructors
| DirExists | |
| DirModTime | |
| DirNotExists |
Instances
| Structured MonitorKindDir # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| Binary MonitorKindDir # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods put :: MonitorKindDir -> Put # get :: Get MonitorKindDir # putList :: [MonitorKindDir] -> Put # | |||||
| Generic MonitorKindDir # | |||||
Defined in Distribution.Simple.FileMonitor.Types Associated Types
| |||||
| Show MonitorKindDir # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods showsPrec :: Int -> MonitorKindDir -> ShowS # show :: MonitorKindDir -> String # showList :: [MonitorKindDir] -> ShowS # | |||||
| Eq MonitorKindDir # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods (==) :: MonitorKindDir -> MonitorKindDir -> Bool # (/=) :: MonitorKindDir -> MonitorKindDir -> Bool # | |||||
| type Rep MonitorKindDir # | |||||
Defined in Distribution.Simple.FileMonitor.Types type Rep MonitorKindDir = D1 ('MetaData "MonitorKindDir" "Distribution.Simple.FileMonitor.Types" "Cabal-3.14.1.0-1c71" 'False) (C1 ('MetaCons "DirExists" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "DirModTime" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "DirNotExists" 'PrefixI 'False) (U1 :: Type -> Type))) | |||||
data MonitorKindFile #
Constructors
| FileExists | |
| FileModTime | |
| FileHashed | |
| FileNotExists |
Instances
| Structured MonitorKindFile # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| Binary MonitorKindFile # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods put :: MonitorKindFile -> Put # get :: Get MonitorKindFile # putList :: [MonitorKindFile] -> Put # | |||||
| Generic MonitorKindFile # | |||||
Defined in Distribution.Simple.FileMonitor.Types Associated Types
Methods from :: MonitorKindFile -> Rep MonitorKindFile x to :: Rep MonitorKindFile x -> MonitorKindFile | |||||
| Show MonitorKindFile # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods showsPrec :: Int -> MonitorKindFile -> ShowS # show :: MonitorKindFile -> String # showList :: [MonitorKindFile] -> ShowS # | |||||
| Eq MonitorKindFile # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods (==) :: MonitorKindFile -> MonitorKindFile -> Bool # (/=) :: MonitorKindFile -> MonitorKindFile -> Bool # | |||||
| type Rep MonitorKindFile # | |||||
Defined in Distribution.Simple.FileMonitor.Types type Rep MonitorKindFile = D1 ('MetaData "MonitorKindFile" "Distribution.Simple.FileMonitor.Types" "Cabal-3.14.1.0-1c71" 'False) ((C1 ('MetaCons "FileExists" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "FileModTime" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "FileHashed" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "FileNotExists" 'PrefixI 'False) (U1 :: Type -> Type))) | |||||
data RootedGlob #
Constructors
| RootedGlob FilePathRoot Glob |
Instances
| Parsec RootedGlob # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods parsec :: CabalParsing m => m RootedGlob # | |||||
| Pretty RootedGlob # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| Structured RootedGlob # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| Binary RootedGlob # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| Generic RootedGlob # | |||||
Defined in Distribution.Simple.FileMonitor.Types Associated Types
| |||||
| Show RootedGlob # | |||||
Defined in Distribution.Simple.FileMonitor.Types Methods showsPrec :: Int -> RootedGlob -> ShowS # show :: RootedGlob -> String # showList :: [RootedGlob] -> ShowS # | |||||
| Eq RootedGlob # | |||||
Defined in Distribution.Simple.FileMonitor.Types | |||||
| type Rep RootedGlob # | |||||
Defined in Distribution.Simple.FileMonitor.Types type Rep RootedGlob = D1 ('MetaData "RootedGlob" "Distribution.Simple.FileMonitor.Types" "Cabal-3.14.1.0-1c71" 'False) (C1 ('MetaCons "RootedGlob" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 FilePathRoot) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Glob))) | |||||
Instances
| Parsec Glob # | |||||
Defined in Distribution.Simple.Glob.Internal Methods parsec :: CabalParsing m => m Glob # | |||||
| Pretty Glob # | |||||
Defined in Distribution.Simple.Glob.Internal | |||||
| Structured Glob # | |||||
Defined in Distribution.Simple.Glob.Internal | |||||
| Binary Glob # | |||||
| Generic Glob # | |||||
Defined in Distribution.Simple.Glob.Internal Associated Types
| |||||
| Show Glob # | |||||
| Eq Glob # | |||||
| type Rep Glob # | |||||
Defined in Distribution.Simple.Glob.Internal type Rep Glob = D1 ('MetaData "Glob" "Distribution.Simple.Glob.Internal" "Cabal-3.14.1.0-1c71" 'False) ((C1 ('MetaCons "GlobDir" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 GlobPieces) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Glob)) :+: C1 ('MetaCons "GlobDirRecursive" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 GlobPieces))) :+: (C1 ('MetaCons "GlobFile" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 GlobPieces)) :+: C1 ('MetaCons "GlobDirTrailing" 'PrefixI 'False) (U1 :: Type -> Type))) | |||||
Creating and checking sets of monitored files
data FileMonitor a b Source #
A monitor for detecting changes to a set of files. It can be used to
efficiently test if any of a set of files (specified individually or by
glob patterns) has changed since some snapshot. In addition, it also checks
for changes in a value (of type a), and when there are no changes in
either it returns a saved value (of type b).
The main use case looks like this: suppose we have some expensive action that depends on certain pure inputs and reads some set of files, and produces some pure result. We want to avoid re-running this action when it would produce the same result. So we need to monitor the files the action looked at, the other pure input values, and we need to cache the result. Then at some later point, if the input value didn't change, and none of the files changed, then we can re-use the cached result rather than re-running the action.
This can be achieved using a FileMonitor. Each FileMonitor instance
saves state in a disk file, so the file for that has to be specified,
making sure it is unique. The pattern is to use checkFileMonitorChanged
to see if there's been any change. If there is, re-run the action, keeping
track of the files, then use updateFileMonitor to record the current
set of files to monitor, the current input value for the action, and the
result of the action.
The typical occurrence of this pattern is captured by rerunIfChanged
and the Rebuild monad. More complicated cases may need to use
checkFileMonitorChanged and updateFileMonitor directly.
Constructors
| FileMonitor | |
Fields
| |
Arguments
| :: Eq a | |
| => FilePath | The file to cache the state of the file monitor. Must be unique. |
| -> FileMonitor a b |
Define a new file monitor.
It's best practice to define file monitor values once, and then use the
same value for checkFileMonitorChanged and updateFileMonitor as this
ensures you get the same types a and b for reading and writing.
The path of the file monitor itself must be unique because it keeps state on disk and these would clash.
data MonitorChanged a b Source #
The result of checkFileMonitorChanged: either the monitored files or
value changed (and it tells us which it was) or nothing changed and we get
the cached result.
Constructors
| MonitorUnchanged b [MonitorFilePath] | The monitored files and value did not change. The cached result is
The set of monitored files is also returned. This is useful
for composing or nesting |
| MonitorChanged (MonitorChangedReason a) | The monitor found that something changed. The reason is given. |
Instances
| (Show b, Show a) => Show (MonitorChanged a b) Source # | |
Defined in Distribution.Client.FileMonitor Methods showsPrec :: Int -> MonitorChanged a b -> ShowS # show :: MonitorChanged a b -> String # showList :: [MonitorChanged a b] -> ShowS # | |
data MonitorChangedReason a Source #
What kind of change checkFileMonitorChanged detected.
Constructors
| MonitoredFileChanged FilePath | One of the files changed (existence, file type, mtime or file
content, depending on the |
| MonitoredValueChanged a | The pure input value changed. The previous cached key value is also returned. This is sometimes
useful when using a |
| MonitorFirstRun | There was no saved monitor state, cached value etc. Ie the file
for the |
| MonitorCorruptCache | There was existing state, but we could not read it. This typically
happens when the code has changed compared to an existing |
Instances
| Functor MonitorChangedReason Source # | |
Defined in Distribution.Client.FileMonitor Methods fmap :: (a -> b) -> MonitorChangedReason a -> MonitorChangedReason b # (<$) :: a -> MonitorChangedReason b -> MonitorChangedReason a # | |
| Show a => Show (MonitorChangedReason a) Source # | |
Defined in Distribution.Client.FileMonitor Methods showsPrec :: Int -> MonitorChangedReason a -> ShowS # show :: MonitorChangedReason a -> String # showList :: [MonitorChangedReason a] -> ShowS # | |
| Eq a => Eq (MonitorChangedReason a) Source # | |
Defined in Distribution.Client.FileMonitor Methods (==) :: MonitorChangedReason a -> MonitorChangedReason a -> Bool # (/=) :: MonitorChangedReason a -> MonitorChangedReason a -> Bool # | |
checkFileMonitorChanged Source #
Arguments
| :: (Binary a, Structured a, Binary b, Structured b) | |
| => FileMonitor a b | cache file path |
| -> FilePath | root directory |
| -> a | guard or key value |
| -> IO (MonitorChanged a b) | did the key or any paths change? |
Test if the input value or files monitored by the FileMonitor have
changed. If not, return the cached value.
See FileMonitor for a full explanation.
Arguments
| :: (Binary a, Structured a, Binary b, Structured b) | |
| => FileMonitor a b | cache file path |
| -> FilePath | root directory |
| -> Maybe MonitorTimestamp | timestamp when the update action started |
| -> [MonitorFilePath] | files of interest relative to root |
| -> a | the current key value |
| -> b | the current result value |
| -> IO () |
Update the input value and the set of files monitored by the
FileMonitor, plus the cached value that may be returned in future.
This takes a snapshot of the state of the monitored files right now, so
checkFileMonitorChanged will look for file system changes relative to
this snapshot.
This is typically done once the action has been completed successfully and
we have the action's result and we know what files it looked at. See
FileMonitor for a full explanation.
If we do take the snapshot after the action has completed then we have a
problem. The problem is that files might have changed while the action was
running but after the action read them. If we take the snapshot after the
action completes then we will miss these changes. The solution is to record
a timestamp before beginning execution of the action and then we make the
conservative assumption that any file that has changed since then has
already changed, ie the file monitor state for these files will be such that
checkFileMonitorChanged will report that they have changed.
So if you do use updateFileMonitor after the action (so you can discover
the files used rather than predicting them in advance) then use
beginUpdateFileMonitor to get a timestamp and pass that. Alternatively,
if you take the snapshot in advance of the action, or you're not monitoring
any files then you can use Nothing for the timestamp parameter.
data MonitorTimestamp Source #
A timestamp to help with the problem of file changes during actions.
See updateFileMonitor for details.
beginUpdateFileMonitor :: IO MonitorTimestamp Source #
Record a timestamp at the beginning of an action, and when the action
completes call updateFileMonitor passing it the timestamp.
See updateFileMonitor for details.
Internal
data MonitorStateFileSet Source #
The state necessary to determine whether a set of monitored files has changed. It consists of two parts: a set of specific files to be monitored (index by their path), and a list of globs, which monitor may files at once.
Instances
| Structured MonitorStateFileSet Source # | |||||
Defined in Distribution.Client.FileMonitor Methods structure :: Proxy MonitorStateFileSet -> Structure structureHash' :: Tagged MonitorStateFileSet MD5 | |||||
| Binary MonitorStateFileSet Source # | |||||
Defined in Distribution.Client.FileMonitor Methods put :: MonitorStateFileSet -> Put # get :: Get MonitorStateFileSet # putList :: [MonitorStateFileSet] -> Put # | |||||
| Generic MonitorStateFileSet Source # | |||||
Defined in Distribution.Client.FileMonitor Associated Types
Methods from :: MonitorStateFileSet -> Rep MonitorStateFileSet x to :: Rep MonitorStateFileSet x -> MonitorStateFileSet | |||||
| Show MonitorStateFileSet Source # | |||||
Defined in Distribution.Client.FileMonitor Methods showsPrec :: Int -> MonitorStateFileSet -> ShowS # show :: MonitorStateFileSet -> String # showList :: [MonitorStateFileSet] -> ShowS # | |||||
| type Rep MonitorStateFileSet Source # | |||||
Defined in Distribution.Client.FileMonitor type Rep MonitorStateFileSet = D1 ('MetaData "MonitorStateFileSet" "Distribution.Client.FileMonitor" "cabal-install-3.14.1.1-81LhcPbQmaYEGrx6eWPlZg" 'False) (C1 ('MetaCons "MonitorStateFileSet" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [MonitorStateFile]) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [MonitorStateGlob]))) | |||||
data MonitorStateFile Source #
The state necessary to determine whether a monitored file has changed.
This covers all the cases of MonitorFilePath except for globs which is
covered separately by MonitorStateGlob.
The Maybe ModTime is to cover the case where we already consider the
file to have changed, either because it had already changed by the time we
did the snapshot (i.e. too new, changed since start of update process) or it
no longer exists at all.
Instances
| Structured MonitorStateFile Source # | |||||
Defined in Distribution.Client.FileMonitor Methods structure :: Proxy MonitorStateFile -> Structure structureHash' :: Tagged MonitorStateFile MD5 | |||||
| Binary MonitorStateFile Source # | |||||
Defined in Distribution.Client.FileMonitor Methods put :: MonitorStateFile -> Put # get :: Get MonitorStateFile # putList :: [MonitorStateFile] -> Put # | |||||
| Generic MonitorStateFile Source # | |||||
Defined in Distribution.Client.FileMonitor Associated Types
Methods from :: MonitorStateFile -> Rep MonitorStateFile x to :: Rep MonitorStateFile x -> MonitorStateFile | |||||
| Show MonitorStateFile Source # | |||||
Defined in Distribution.Client.FileMonitor Methods showsPrec :: Int -> MonitorStateFile -> ShowS # show :: MonitorStateFile -> String # showList :: [MonitorStateFile] -> ShowS # | |||||
| type Rep MonitorStateFile Source # | |||||
Defined in Distribution.Client.FileMonitor type Rep MonitorStateFile | |||||
data MonitorStateGlob Source #
The state necessary to determine whether the files matched by a globbing match have changed.
Instances
| Structured MonitorStateGlob Source # | |||||
Defined in Distribution.Client.FileMonitor Methods structure :: Proxy MonitorStateGlob -> Structure structureHash' :: Tagged MonitorStateGlob MD5 | |||||
| Binary MonitorStateGlob Source # | |||||
Defined in Distribution.Client.FileMonitor Methods put :: MonitorStateGlob -> Put # get :: Get MonitorStateGlob # putList :: [MonitorStateGlob] -> Put # | |||||
| Generic MonitorStateGlob Source # | |||||
Defined in Distribution.Client.FileMonitor Associated Types
Methods from :: MonitorStateGlob -> Rep MonitorStateGlob x to :: Rep MonitorStateGlob x -> MonitorStateGlob | |||||
| Show MonitorStateGlob Source # | |||||
Defined in Distribution.Client.FileMonitor Methods showsPrec :: Int -> MonitorStateGlob -> ShowS # show :: MonitorStateGlob -> String # showList :: [MonitorStateGlob] -> ShowS # | |||||
| type Rep MonitorStateGlob Source # | |||||
Defined in Distribution.Client.FileMonitor type Rep MonitorStateGlob | |||||