module B9.Repository
( RepoCacheReader,
getRepoCache,
withSelectedRemoteRepo,
getSelectedRemoteRepo,
SelectedRemoteRepoReader,
Repository (..),
RepoImagesMap,
toRemoteRepository,
SelectedRemoteRepo (..),
remoteRepoCacheDir,
localRepoDir,
lookupRemoteRepo,
filterRepoImagesMap,
lookupCachedImages,
allCachedSharedImages,
allSharedImagesWithRepo,
maxSharedImageOfAllRepos,
allSharedImagesInRepo,
allSharedImages,
allRepositories,
groupBySharedImageName,
keepNLatestSharedImages,
dropAllButNLatestSharedImages,
module X,
)
where
import B9.B9Config
import B9.B9Config.Repository as X
import B9.B9Error
import B9.DiskImages
import Control.Eff
import Control.Eff.Reader.Lazy
import Data.Foldable
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
import GHC.Generics
import System.FilePath
import Test.QuickCheck
import Text.Printf
data Repository
= Cache
| Remote String
deriving (Eq, Ord, Read, Show, Generic)
instance Arbitrary Repository where
arbitrary =
Test.QuickCheck.oneof
[ pure Cache,
Remote . printf "remote-repo-%0X" <$> choose (0, 31 :: Int)
]
instance Function Repository
instance CoArbitrary Repository
toRemoteRepository :: RemoteRepo -> Repository
toRemoteRepository = Remote . remoteRepoRepoId
type RepoCacheReader = Reader RepoCache
getRepoCache :: Member RepoCacheReader e => Eff e RepoCache
getRepoCache = ask
withSelectedRemoteRepo ::
(Member B9ConfigReader e, Member ExcB9 e) =>
Eff (SelectedRemoteRepoReader ': e) a ->
Eff e a
withSelectedRemoteRepo e = do
remoteRepos' <- _remoteRepos <$> getB9Config
mSelectedRepoName <- _repository <$> getB9Config
case mSelectedRepoName of
Nothing -> runReader (MkSelectedRemoteRepo Nothing) e
Just selectedRepoName ->
case lookupRemoteRepo remoteRepos' selectedRepoName of
Nothing ->
throwB9Error
( printf
"selected remote repo '%s' not configured, valid remote repos are: '%s'"
(show selectedRepoName)
(show remoteRepos')
)
Just r -> runReader (MkSelectedRemoteRepo (Just r)) e
newtype SelectedRemoteRepo = MkSelectedRemoteRepo {fromSelectedRemoteRepo :: Maybe RemoteRepo}
type SelectedRemoteRepoReader = Reader SelectedRemoteRepo
getSelectedRemoteRepo ::
Member SelectedRemoteRepoReader e => Eff e SelectedRemoteRepo
getSelectedRemoteRepo = ask
remoteRepoCacheDir ::
RepoCache ->
String ->
FilePath
remoteRepoCacheDir (RepoCache cacheDir) repoId =
cacheDir </> "remote-repos" </> repoId
localRepoDir ::
RepoCache ->
FilePath
localRepoDir (RepoCache cacheDir) = cacheDir </> "local-repo"
lookupRemoteRepo :: Set RemoteRepo -> String -> Maybe RemoteRepo
lookupRemoteRepo repos repoId = Map.lookup repoId repoIdRepoPairs
where
repoIdRepoPairs =
Map.fromList (map (\r@(RemoteRepo rid _ _ _ _) -> (rid, r)) (toList repos))
type RepoImagesMap = Map Repository (Set SharedImage)
filterRepoImagesMap ::
(Repository -> Bool) ->
(SharedImage -> Bool) ->
RepoImagesMap ->
RepoImagesMap
filterRepoImagesMap repoPred imgPred =
Map.map (Set.filter imgPred)
. Map.filterWithKey (const . repoPred)
lookupCachedImages ::
SharedImageName ->
RepoImagesMap ->
Set SharedImage
lookupCachedImages name =
allSharedImages
. filterRepoImagesMap (== Cache) ((== name) . sharedImageName)
allRepositories :: RepoImagesMap -> Set Repository
allRepositories = Map.keysSet
allSharedImages :: RepoImagesMap -> Set SharedImage
allSharedImages = fold
allSharedImagesWithRepo :: RepoImagesMap -> Set (SharedImage, Repository)
allSharedImagesWithRepo = Map.foldMapWithKey (Set.map . flip (,))
maxSharedImageOfAllRepos :: RepoImagesMap -> Maybe (SharedImage, Repository)
maxSharedImageOfAllRepos = Set.lookupMax . allSharedImagesWithRepo
allSharedImagesInRepo :: Repository -> RepoImagesMap -> Set SharedImage
allSharedImagesInRepo repo = fromMaybe Set.empty . Map.lookup repo
allCachedSharedImages ::
RepoImagesMap ->
Set SharedImage
allCachedSharedImages = allSharedImagesInRepo Cache
keepNLatestSharedImages :: Int -> Set SharedImage -> Set SharedImage
keepNLatestSharedImages n =
fold
. Map.map
( \s ->
let nOld = max 0 (length s - n)
in Set.drop nOld s
)
. groupBySharedImageName
dropAllButNLatestSharedImages :: Int -> Set SharedImage -> Set SharedImage
dropAllButNLatestSharedImages n =
fold
. Map.map
( \s ->
let nOld = max 0 (length s - n)
in Set.take nOld s
)
. groupBySharedImageName
groupBySharedImageName :: Set SharedImage -> Map SharedImageName (Set SharedImage)
groupBySharedImageName =
foldr
( \img ->
Map.alter
( Just
. maybe
(Set.singleton img)
(Set.insert img)
)
(sharedImageName img)
)
Map.empty