hackage-server-0.5.0: Distribution/Server/Features/HaskellPlatform.hs
{-# LANGUAGE RankNTypes, NamedFieldPuns, RecordWildCards #-}
module Distribution.Server.Features.HaskellPlatform (
PlatformFeature,
PlatformResource(..),
initPlatformFeature,
) where
import Distribution.Server.Framework
import Distribution.Server.Framework.BackupRestore
import Distribution.Server.Features.HaskellPlatform.State
import Distribution.Package
import Distribution.Version
import Distribution.Text
import Data.Function
import qualified Data.Map as Map
import qualified Data.Set as Set
-- Note: this can be generalized into dividing Hackage up into however many
-- subsets of packages are desired. One could implement a Debian-esque system
-- with this sort of feature.
--
data PlatformFeature = PlatformFeature {
platformFeatureInterface :: HackageFeature,
platformResource :: PlatformResource,
platformVersions :: MonadIO m => PackageName -> m [Version],
platformPackageLatest :: MonadIO m => m [(PackageName, Version)],
setPlatform :: MonadIO m => PackageName -> [Version] -> m (),
removePlatform :: MonadIO m => PackageName -> m ()
}
instance IsHackageFeature PlatformFeature where
getFeatureInterface = platformFeatureInterface
data PlatformResource = PlatformResource {
platformPackage :: Resource,
platformPackages :: Resource,
platformPackageUri :: String -> PackageName -> String,
platformPackagesUri :: String -> String
}
initPlatformFeature :: ServerEnv -> IO (IO PlatformFeature)
initPlatformFeature ServerEnv{serverStateDir} = do
platformState <- platformStateComponent serverStateDir
return $ do
let feature = platformFeature platformState
return feature
platformStateComponent :: FilePath -> IO (StateComponent AcidState PlatformPackages)
platformStateComponent stateDir = do
st <- openLocalStateFrom (stateDir </> "db" </> "PlatformPackages") initialPlatformPackages
return StateComponent {
stateDesc = "Platform packages"
, stateHandle = st
, getState = query st GetPlatformPackages
, putState = update st . ReplacePlatformPackages
, resetState = platformStateComponent
-- TODO: backup
-- For now backup is just empty, as this package is basically featureless
-- It defines state, but there is no way at all to modify this state
, backupState = \_ _ -> []
, restoreState = RestoreBackup {
restoreEntry = error "Unexpected backup entry for platform"
, restoreFinalize = return initialPlatformPackages
}
}
platformFeature :: StateComponent AcidState PlatformPackages
-> PlatformFeature
platformFeature platformState
= PlatformFeature{..}
where
platformFeatureInterface = (emptyHackageFeature "platform") {
featureDesc = "List packages which are part of the Haskell platform (this is work in progress)"
, featureResources =
map ($ platformResource) [
platformPackage
, platformPackages
]
, featureState = [abstractAcidStateComponent platformState]
}
platformResource = fix $ \r -> PlatformResource
{ platformPackage = (resourceAt "/platform/package/:package.:format") {
resourceGet = []
, resourceDelete = []
, resourcePut = []
}
, platformPackages = (resourceAt "/platform/.:format") {
resourceGet = []
, resourcePost = []
}
, platformPackageUri = \format pkgid ->
renderResource (platformPackage r) [display pkgid, format]
, platformPackagesUri = \format ->
renderResource (platformPackages r) [format]
-- and maybe "/platform/haskell-platform.cabal"
}
------------------------------------------
-- functionality: showing status for a single package, and for all packages, adding a package, deleting a package
platformVersions :: MonadIO m => PackageName -> m [Version]
platformVersions pkgname = liftM Set.toList $ queryState platformState $ GetPlatformPackage pkgname
platformPackageLatest :: MonadIO m => m [(PackageName, Version)]
platformPackageLatest = liftM (Map.toList . Map.map Set.findMax . blessedPackages) $ queryState platformState $ GetPlatformPackages
setPlatform :: MonadIO m => PackageName -> [Version] -> m ()
setPlatform pkgname versions = updateState platformState $ SetPlatformPackage pkgname (Set.fromList versions)
removePlatform :: MonadIO m => PackageName -> m ()
removePlatform pkgname = updateState platformState $ SetPlatformPackage pkgname Set.empty