module-management-0.20.2: testdata/debian/Debian/Repo/State/AptImage.hs
{-# LANGUAGE FlexibleInstances, OverloadedStrings, PackageImports, ScopedTypeVariables, TemplateHaskell #-}
{-# OPTIONS -Wall -fno-warn-orphans #-}
module Debian.Repo.State.AptImage
( withAptImage
, aptSourcePackages
, aptBinaryPackages
, prepareSource
) where
import Control.Applicative ((<$>))
import Control.Exception (SomeException)
import Control.Monad.Catch (MonadCatch, catch)
import Control.Monad.State (StateT)
import Control.Monad.Trans (MonadIO(..), MonadTrans(lift))
import Data.List (sort)
import Data.Maybe (listToMaybe)
import Debian.Changes (ChangeLogEntry(logVersion))
import Debian.Pretty (ppDisplay)
import Debian.Relation (SrcPkgName(unSrcPkgName))
import Debian.Release (ReleaseName)
import Debian.Repo.AptImage (aptDir, aptGetSource, aptGetUpdate)
import Debian.Repo.EnvPath (EnvRoot(rootPath))
import Debian.Repo.Internal.Apt (AptImage(aptImageArch, aptImageRoot, aptImageSources,
aptBinaryPackageCache, aptSourcePackageCache),
cacheRootDir, createAptImage, MonadApt(..), modifyApt)
import Debian.Repo.Internal.Repos (AptKey, evalMonadApt, getAptKey, MonadRepos(..), putAptImage)
import Debian.Repo.PackageID (PackageID(packageName), PackageID(packageVersion))
import Debian.Repo.PackageIndex (BinaryPackage, SourcePackage(sourcePackageID))
import Debian.Repo.Prelude (symbol)
import Debian.Repo.Prelude.Verbosity (qPutStr, qPutStrLn)
import Debian.Repo.Slice (NamedSliceList(sliceList, sliceListName), SliceList, SourcesChangedAction)
import Debian.Repo.SourceTree (DebianBuildTree(debTree'), DebianSourceTree(tree'), HasChangeLog(entry), findDebianBuildTrees, SourceTree(dir'))
import Debian.Repo.State.PackageIndex (binaryPackagesFromSources, sourcePackagesFromSources)
import Debian.Repo.State.Slice (updateCacheSources)
import Debian.Repo.Top (MonadTop)
import Debian.Version (DebianVersion)
import System.Directory (createDirectoryIfMissing)
import System.Unix.Directory (removeRecursiveSafely)
instance MonadApt m => MonadApt (StateT EnvRoot m) where
getApt = lift getApt
putApt = lift . putApt
instance MonadRepos m => MonadRepos (StateT AptImage m) where
getRepos = lift getRepos
putRepos = lift . putRepos
withAptImage :: (MonadRepos m, MonadTop m) => SourcesChangedAction -> NamedSliceList -> StateT AptImage m a -> m a
withAptImage sourcesChangedAction sources action = prepareAptImage sourcesChangedAction sources >>= evalMonadApt action
-- |Create a skeletal enviroment sufficient to run apt-get.
prepareAptImage :: forall m. (MonadTop m, MonadRepos m) =>
SourcesChangedAction -- What to do if environment already exists and sources.list is different
-> NamedSliceList -- The sources.list
-> m AptKey -- The resulting environment
prepareAptImage sourcesChangedAction sources = do
mkey <- getAptKey =<< cacheRootDir (sliceListName sources)
maybe (prepareAptImage' sourcesChangedAction sources) return mkey
prepareAptImage' :: forall m. (MonadCatch m, MonadTop m, MonadRepos m) => SourcesChangedAction -> NamedSliceList -> m AptKey
prepareAptImage' sourcesChangedAction sources = do
mkey <- getAptKey =<< cacheRootDir (sliceListName sources)
maybe (prepareAptImage'' `catch` handle) return mkey
where
handle :: SomeException -> m AptKey
handle e = do
qPutStrLn ("Exception preparing " ++ (ppDisplay . sliceListName $ sources) ++ ": " ++ show e)
removeAptImage
prepareAptImage''
prepareAptImage'' = do
qPutStrLn ($(symbol 'prepareAptImage) ++ ": " ++ (ppDisplay . sliceListName $ sources))
key <- putAptImage =<< createAptImage sources
evalMonadApt (updateCacheSources sourcesChangedAction sources >> aptGetUpdate) key
return key
removeAptImage = cacheRootDir (sliceListName sources) >>= liftIO . removeRecursiveSafely . rootPath
-- |Run apt-get update and then retrieve all the packages referenced
-- by the sources.list. The source packages are sorted so that
-- packages with the same name are together with the newest first.
-- updateAptEnv :: (MonadRepos m, MonadApt m) => m ()
-- updateAptEnv = aptGetUpdate
aptSourcePackages :: (MonadRepos m, MonadApt m) => m [SourcePackage]
aptSourcePackages = do
mpkgs <- aptSourcePackageCache <$> getApt
maybe aptSourcePackages' return mpkgs
where
aptSourcePackages' = do
root <- aptImageRoot <$> getApt
arch <- aptImageArch <$> getApt
sources <- aptImageSources <$> getApt
-- qPutStrLn ($(symbol 'aptSourcePackages) ++ " " ++ show (pretty (sliceListName sources)))
pkgs <- sourcePackagesFromSources root arch (sliceList sources)
modifyApt (\ s -> s {aptSourcePackageCache = Just pkgs})
return pkgs
aptBinaryPackages :: (MonadRepos m, MonadApt m) => m [BinaryPackage]
aptBinaryPackages = do
mpkgs <- aptBinaryPackageCache <$> getApt
maybe aptBinaryPackages' return mpkgs
where
aptBinaryPackages' = do
root <- aptImageRoot <$> getApt
arch <- aptImageArch <$> getApt
sources <- aptImageSources <$> getApt
-- qPutStrLn ($(symbol 'aptBinaryPackages) ++ " " ++ show (pretty (sliceListName sources)))
pkgs <- binaryPackagesFromSources root arch (sliceList sources)
modifyApt (\ s -> s {aptBinaryPackageCache = Just pkgs})
return pkgs
{-
do qPutStrLn "AptImage.getBinaryPackages"
root <- getL aptImageRoot <$> getApt
arch <- getL aptImageArch <$> getApt
sources <- (sliceList . getL aptImageSources) <$> getApt
binaryPackagesFromSources root arch sources
-}
data UpdateError
= Changed ReleaseName FilePath SliceList SliceList
| Missing ReleaseName FilePath
| Flushed
instance Show UpdateError where
show (Changed r p l1 l2) = unwords ["Changed", show r, show p, ppDisplay l1, ppDisplay l2]
show (Missing r p) = unwords ["Missing", show r, show p]
show Flushed = "Flushed"
-- |Retrieve a source package via apt-get.
prepareSource :: (MonadRepos m, MonadApt m, MonadTop m, MonadIO m) =>
SrcPkgName -- The name of the package
-> Maybe DebianVersion -- The desired version, if Nothing get newest
-> m DebianBuildTree -- The resulting source tree
prepareSource package version =
do root <- (rootPath . aptImageRoot) <$> getApt
dir <- aptDir package
liftIO $ createDirectoryIfMissing True dir
ready <- liftIO $ findDebianBuildTrees dir
version' <- latestVersion package version
case (version', ready) of
(Nothing, _) ->
fail $ "No available versions of " ++ unSrcPkgName package ++ " in " ++ root
(Just requested, [tree])
| requested == (logVersion . entry $ tree) ->
return tree
(Just requested, []) ->
do aptGetSource dir [(package, Just requested)]
trees <- liftIO $ findDebianBuildTrees dir
case trees of
[tree] -> return tree
_ -> fail $ "apt-get source failed in " ++ dir ++ " (1): trees=" ++ show (map (dir' . tree' . debTree') trees)
(Just requested, _) ->
do -- One or more incorrect versions are available, remove them
liftIO $ removeRecursiveSafely dir
qPutStr $ "Retrieving APT source for " ++ unSrcPkgName package
aptGetSource dir [(package, Just requested)]
trees <- liftIO $ findDebianBuildTrees dir
case trees of
[tree] -> return tree
_ -> fail $ "apt-get source failed (2): trees=" ++ show (map (dir' . tree' . debTree') trees)
-- | Find the most recent version of a source package.
latestVersion :: (MonadRepos m, MonadApt m) => SrcPkgName -> Maybe DebianVersion -> m (Maybe DebianVersion)
latestVersion package exact = do
pkgs <- aptSourcePackages
let versions = map (packageVersion . sourcePackageID) $ filter ((== package) . packageName . sourcePackageID) $ pkgs
newest = listToMaybe $ reverse $ sort $ versions
return $ maybe newest Just exact