sourcecode:
|
module CPM.Repository.CacheFile
( readRepository )
where
import Data.Maybe ( maybeToList, listToMaybe )
import System.Directory ( doesFileExist )
import System.IO
import ReadShowTerm ( showTerm, readUnqualifiedTerm )
import CPM.Config ( Config, repositoryDir )
import CPM.ConfigPackage ( packageVersion )
import CPM.ErrorLogger
import CPM.Package
import CPM.Repository
------------------------------------------------------------------------------
--- Reads all package specifications from the default repository.
--- Uses the cache if it is present or update the cache after reading.
--- If some errors occur, show them and terminate with error exit status.
---
--- @param cfg - the configuration to use
--- @param large - if true reads the larger cache with more package information
--- (e.g., for searching all packages)
readRepository :: Config -> Bool -> ErrorLogger Repository
readRepository cfg large = do
warnIfRepositoryOld cfg
mbrepo <- readRepositoryCache cfg large
case mbrepo of
Nothing -> do
repo <- readRepositoryFrom (repositoryDir cfg)
logInfo $ "Writing " ++ (if large then "large" else "base") ++
" repository cache..."
liftIOEL $ writeRepositoryCache cfg large repo
return repo
Just repo -> return repo
--- The file containing the repository cache as a Curry term.
repositoryCache :: Config -> Bool -> String
repositoryCache cfg large =
repositoryCacheFilePrefix cfg ++ (if large then "_LARGE" else "_SMALL")
--- The first line of the repository cache (to check version compatibility):
repoCacheVersion :: String
repoCacheVersion = packageVersion ++ "-1"
--- Stores the given repository in the cache.
---
--- @param cfg - the configuration to use
--- @param large - if true writes the larger cache with more package information
--- (e.g., for searching all packages)
--- @param repo - the repository to write
writeRepositoryCache :: Config -> Bool -> Repository -> IO ()
writeRepositoryCache cfg large repo =
writeFile (repositoryCache cfg large) $ unlines $
repoCacheVersion :
map (if large then showTerm . package2largetuple
else showTerm . package2smalltuple)
(allPackages repo)
where
package2smalltuple p =
( name p, version p, dependencies p, compilerCompatibility p )
package2largetuple p =
(package2smalltuple p,
(synopsis p, category p, sourceDirs p, exportedModules p,
listToMaybe (executableSpec p)))
--- Reads the given repository from the cache.
---
--- @param cfg - the configuration to use
--- @param large - if true reads the larger cache with more package information
--- (e.g., for searching all packages)
readRepositoryCache :: Config -> Bool -> ErrorLogger (Maybe Repository)
readRepositoryCache cfg large = do
let cf = repositoryCache cfg large
excache <- liftIOEL $ doesFileExist cf
if excache
then do logDebug ("Reading repository cache from '" ++ cf ++ "'...")
((if large
then readTermInCacheFile cfg (largetuple2package . uread) cf
else readTermInCacheFile cfg (smalltuple2package . uread) cf)
>>= \repo ->
logDebug "Finished reading repository cache" >> return repo)
<|>
(do logInfo "Cleaning broken repository cache..."
cleanRepositoryCache cfg
return Nothing )
else return Nothing
where
uread s = readUnqualifiedTerm ["CPM.Package","Prelude"] s
smalltuple2package (nm,vs,dep,cmp) =
emptyPackage { name = nm
, version = vs
, dependencies = dep
, compilerCompatibility = cmp
}
largetuple2package (basics,(sy,cat,srcs,exps,exec)) =
(smalltuple2package basics)
{ synopsis = sy
, category = cat
, sourceDirs = srcs
, exportedModules = exps
, executableSpec = maybeToList exec
}
readTermInCacheFile :: Config -> (String -> Package) -> String
-> ErrorLogger (Maybe Repository)
readTermInCacheFile cfg trans cf = do
h <- liftIOEL $ openFile cf ReadMode
pv <- liftIOEL $ hGetLine h
if pv == repoCacheVersion
then liftIOEL (hGetContents h) >>= \t ->
return $!! Just (pkgsToRepository (map trans (lines t)))
else do logInfo "Cleaning repository cache (wrong version)..."
cleanRepositoryCache cfg
return Nothing
------------------------------------------------------------------------------
|