cabal-install-3.8.1.0: The command-line interface for Cabal and Hackage.
Safe HaskellNone
LanguageHaskell2010

Distribution.Client.FileMonitor

Description

An abstraction to help with re-running actions when files or other input values they depend on have changed.

Synopsis

Declaring files to monitor

data MonitorFilePath Source #

A description of a file (or set of files) to monitor for changes.

Where file paths are relative they are relative to a common directory (e.g. project root), not necessarily the process current directory.

Instances

Instances details
Eq MonitorFilePath Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Show MonitorFilePath Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Generic MonitorFilePath Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Associated Types

type Rep MonitorFilePath :: Type -> Type #

Binary MonitorFilePath Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Structured MonitorFilePath Source # 
Instance details

Defined in Distribution.Client.FileMonitor

type Rep MonitorFilePath Source # 
Instance details

Defined in Distribution.Client.FileMonitor

type Rep MonitorFilePath = D1 ('MetaData "MonitorFilePath" "Distribution.Client.FileMonitor" "cabal-install-3.8.1.0-7iNu5HGLMqL9QLfLAUJqbd" '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 FilePathGlob))))

data MonitorKindFile Source #

Instances

Instances details
Eq MonitorKindFile Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Show MonitorKindFile Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Generic MonitorKindFile Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Associated Types

type Rep MonitorKindFile :: Type -> Type #

Binary MonitorKindFile Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Structured MonitorKindFile Source # 
Instance details

Defined in Distribution.Client.FileMonitor

type Rep MonitorKindFile Source # 
Instance details

Defined in Distribution.Client.FileMonitor

type Rep MonitorKindFile = D1 ('MetaData "MonitorKindFile" "Distribution.Client.FileMonitor" "cabal-install-3.8.1.0-7iNu5HGLMqL9QLfLAUJqbd" '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 MonitorKindDir Source #

Instances

Instances details
Eq MonitorKindDir Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Show MonitorKindDir Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Generic MonitorKindDir Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Associated Types

type Rep MonitorKindDir :: Type -> Type #

Binary MonitorKindDir Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Structured MonitorKindDir Source # 
Instance details

Defined in Distribution.Client.FileMonitor

type Rep MonitorKindDir Source # 
Instance details

Defined in Distribution.Client.FileMonitor

type Rep MonitorKindDir = D1 ('MetaData "MonitorKindDir" "Distribution.Client.FileMonitor" "cabal-install-3.8.1.0-7iNu5HGLMqL9QLfLAUJqbd" '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 FilePathGlob Source #

A file path specified by globbing

Instances

Instances details
Eq FilePathGlob Source # 
Instance details

Defined in Distribution.Client.Glob

Show FilePathGlob Source # 
Instance details

Defined in Distribution.Client.Glob

Generic FilePathGlob Source # 
Instance details

Defined in Distribution.Client.Glob

Associated Types

type Rep FilePathGlob :: Type -> Type #

Binary FilePathGlob Source # 
Instance details

Defined in Distribution.Client.Glob

Structured FilePathGlob Source # 
Instance details

Defined in Distribution.Client.Glob

Parsec FilePathGlob Source # 
Instance details

Defined in Distribution.Client.Glob

Pretty FilePathGlob Source # 
Instance details

Defined in Distribution.Client.Glob

type Rep FilePathGlob Source # 
Instance details

Defined in Distribution.Client.Glob

type Rep FilePathGlob = D1 ('MetaData "FilePathGlob" "Distribution.Client.Glob" "cabal-install-3.8.1.0-7iNu5HGLMqL9QLfLAUJqbd" 'False) (C1 ('MetaCons "FilePathGlob" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 FilePathRoot) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 FilePathGlobRel)))

monitorFile :: FilePath -> MonitorFilePath Source #

Monitor a single file for changes, based on its modification time. The monitored file is considered to have changed if it no longer exists or if its modification time has changed.

monitorFileHashed :: FilePath -> MonitorFilePath Source #

Monitor a single file for changes, based on its modification time and content hash. The monitored file is considered to have changed if it no longer exists or if its modification time and content hash have changed.

monitorNonExistentFile :: FilePath -> MonitorFilePath Source #

Monitor a single non-existent file for changes. The monitored file is considered to have changed if it exists.

monitorFileExistence :: FilePath -> MonitorFilePath Source #

Monitor a single file for existence only. The monitored file is considered to have changed if it no longer exists.

monitorDirectory :: FilePath -> MonitorFilePath Source #

Monitor a single directory for changes, based on its modification time. The monitored directory is considered to have changed if it no longer exists or if its modification time has changed.

monitorNonExistentDirectory :: FilePath -> MonitorFilePath Source #

Monitor a single non-existent directory for changes. The monitored directory is considered to have changed if it exists.

monitorDirectoryExistence :: FilePath -> MonitorFilePath Source #

Monitor a single directory for existence. The monitored directory is considered to have changed only if it no longer exists.

monitorFileOrDirectory :: FilePath -> MonitorFilePath Source #

Monitor a single file or directory for changes, based on its modification time. The monitored file is considered to have changed if it no longer exists or if its modification time has changed.

monitorFileGlob :: FilePathGlob -> MonitorFilePath Source #

Monitor a set of files (or directories) identified by a file glob. The monitored glob is considered to have changed if the set of files matching the glob changes (i.e. creations or deletions), or for files if the modification time and content hash of any matching file has changed.

monitorFileGlobExistence :: FilePathGlob -> MonitorFilePath Source #

Monitor a set of files (or directories) identified by a file glob for existence only. The monitored glob is considered to have changed if the set of files matching the glob changes (i.e. creations or deletions).

monitorFileSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath] Source #

Creates a list of files to monitor when you search for a file which unsuccessfully looked in notFoundAtPaths before finding it at foundAtPath.

monitorFileHashedSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath] Source #

Similar to monitorFileSearchPath, but also instructs us to monitor the hash of the found file.

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

newFileMonitor Source #

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 b.

The set of monitored files is also returned. This is useful for composing or nesting FileMonitors.

MonitorChanged (MonitorChangedReason a)

The monitor found that something changed. The reason is given.

Instances

Instances details
(Show b, Show a) => Show (MonitorChanged a b) Source # 
Instance details

Defined in Distribution.Client.FileMonitor

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 MonitorFilePath in question)

MonitoredValueChanged a

The pure input value changed.

The previous cached key value is also returned. This is sometimes useful when using a fileMonitorKeyValid function that is not simply (==), when invalidation can be partial. In such cases it can make sense to updateFileMonitor with a key value that's a combination of the new and old (e.g. set union).

MonitorFirstRun

There was no saved monitor state, cached value etc. Ie the file for the FileMonitor does not exist.

MonitorCorruptCache

There was existing state, but we could not read it. This typically happens when the code has changed compared to an existing FileMonitor cache file and type of the input value or cached value has changed such that we cannot decode the values. This is completely benign as we can treat is just as if there were no cache file and re-run.

checkFileMonitorChanged Source #

Arguments

:: forall a b. (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.

updateFileMonitor Source #

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

Instances details
Show MonitorStateFileSet Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Generic MonitorStateFileSet Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Associated Types

type Rep MonitorStateFileSet :: Type -> Type #

Binary MonitorStateFileSet Source # 
Instance details

Defined in Distribution.Client.FileMonitor

Structured MonitorStateFileSet Source # 
Instance details

Defined in Distribution.Client.FileMonitor

type Rep MonitorStateFileSet Source # 
Instance details

Defined in Distribution.Client.FileMonitor

type Rep MonitorStateFileSet = D1 ('MetaData "MonitorStateFileSet" "Distribution.Client.FileMonitor" "cabal-install-3.8.1.0-7iNu5HGLMqL9QLfLAUJqbd" '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.

data MonitorStateGlob Source #

The state necessary to determine whether the files matched by a globbing match have changed.