-
Notifications
You must be signed in to change notification settings - Fork 199
Architecture: hooks
The core hook types are defined in Distribution.Server.Hook
, but they are available from a variety of features.
Presently, Hooks are used to keep features in sync. This is important because features often keep their own Map PackageName Blah
to mirror the central one. They're used for push-caching as well in some cases.
The array of hooks offered by a feature are, as with any web framework, informed by the features that depend on it. Try to think of what might use your data, and when it might need to be updated.
Also, before modifying data from another feature, see if there are any hooks you need to call as well. Even better, provide wrappers around updates to automatically call the hooks.
-
CoreFeature
provides a lot of them. Any features that update the core data set should call them appropriately. (Either that, or more wrapper functions which call them automatically.)-
packageAddHook :: Hook (PkgInfo -> IO ())
. This is called when a package name and version is added to the index which was not there previously. -
packageRemoveHook :: Hook (PkgInfo -> IO ())
. Called when a package name and version is totally wiped from the index (should be a rare occurence). It is sometimes annoying to implement removal for auxiliary indices, but it helps ensure feature consistency. -
packageChangeHook :: Hook (PkgInfo -> PkgInfo -> IO ())
. Called when a package name and version is replaced from an old value (first argument) to a new one (second argument). -
packageIndexChange :: Hook (IO ())
: Called whenever the index tarball needs to be changed. Dubious. -
newPackageHook :: Hook (PkgInfo -> IO ())
: Called after packageAddHook only if this is the first version of this package to be put in the main index. -
noPackageHook :: Hook (PkgInfo -> IO ())
. Called after packageRemoveHook only if there are no more versions of that package left in the main index. -
tarballDownload :: Hook (PackageId -> IO ())
. Called whenever a package tarball is downloaded.
-
-
UserFeature
provides:-
userAdded :: Hook (IO ())
. More hooks to come.
-
-
VersionsFeature
provides:-
preferredHook :: Hook (PackageName -> PreferredInfo -> IO ())
. Called whenever the preferred versions for a package is updated. -
deprecatedHook :: Hook (PackageName -> Maybe [PackageName] -> IO ())
. Called whenever a package is deprecated (in favor ofJust pkgs
) or undeprecated (Nothing
).
-
-
TagsFeature
provides:-
tagsUpdated :: Hook (Set PackageName -> Set Tag -> IO ())
. Called whenever tags are updated. The first argument is all packages affected and the second argument is all tags affected. In most cases one of these will be a singleton set.
-
-
ReverseFeature
provides:-
reverseUpdateHook :: Hook (Map PackageName [Version] -> IO ())
. Called whenever the reverse package index is updated. It lists the packages whose revdeps index was updated, and for those packages, which versions were affected.
-
Relevant definitions:
data Hook a = Hook (IORef [a])
newHook :: IO (Hook a)
registerHook :: Hook a -> a -> IO ()
registerHook (Hook list) hook = modifyIORef list (hook:)
runHooks :: MonadIO m => Hook a -> (a -> IO b) -> m ()
runHook :: MonadIO m => Hook (IO ()) -> m ()
runHook' :: MonadIO m => Hook (a -> IO ()) -> a -> m ()
runHook'' :: MonadIO m => Hook (a -> b -> IO ()) -> a -> b -> m ()
A filter is a special type of hook that retrieves a result. They should be used, for the most part, to forbid or permit certain actions from happening. Try not to use them to modify a view of data on the fly (e.g., BlahRender -> IO BlahRender
); introduce new wrapper view data structures if necessary, which the view modules could use instead.
-
UploadFeature
provides:-
canUploadPackage :: Filter (UserId -> UploadResult -> IO (Maybe ErrorResponse))
. Called before adding a package to the main index. It uses theUploadResult
type, which previews the cabal file,GenericPackageDescription
, and any upload warnings. If anErrorResponse
results, the operation is aborted.
-
-
UserFeature
provides:-
packageMutate :: Filter (UserId -> IO Bool)
. Called whenever updating any kind of package index, even a non-main one. This can be used to let anyone use the social features, but only let approved people upload packages, which is the current system as of August 2010.
-
Relevant definitions:
type Filter a = Hook a
newHook :: IO (Hook a)
registerHook :: Hook a -> a -> IO ()
runFilters :: MonadIO m => Filter a -> (a -> IO b) -> m [b]
runFilter :: MonadIO m => Filter (IO a) -> m [a]
runFilter' :: MonadIO m => Filter (a -> IO b) -> a -> m [b]
runFilter'' :: MonadIO m => Filter (a -> b -> IO c) -> a -> b -> m [c]