Description
We have
data ProgramDb = ProgramDb
{ unconfiguredProgs :: UnconfiguredProgs
, progSearchPath :: ProgramSearchPath
, configuredProgs :: ConfiguredProgs
}
-- | Note that this instance does not preserve the known 'Program's.
-- See 'restoreProgramDb' for details.
instance Binary ProgramDb where
put db = do
put (progSearchPath db)
put (configuredProgs db)
get = do
searchpath <- get
progs <- get
return $!
emptyProgramDb
{ progSearchPath = searchpath
, configuredProgs = progs
}
Note here that the Binary
instance for ProgramDb
discards the unconfigured programs. This is because arbitrary functions can be stored in that field (e.g. programFindVersion :: Verbosity -> FilePath -> IO (Maybe Version)
).
However, this easily leads to bugs; #2241 was an example. I ran into another bug today, which was that the configureCompiler
function in cabal-install
would also drop unconfigured programs, which could lead to e.g. failing to find the ar
executable (The program 'ar' is required but it could not be found.
).
One first step which could help avoiding bugs is to define a newtype around ProgramDb
and attach the Binary
instance to that newtype instead. The wrapping/unwrapping of the newtype would hopefully introduce the appropriate amount of ceremony to avoid accidents.
More ambitiously, we could re-design ProgramDb
, e.g. by introducing a serialisable DSL for unconfigured programs, or perhaps by using static pointers.