diff --git a/benchmarks/RevDeps.hs b/benchmarks/RevDeps.hs index 25e3222c3..4585306ab 100644 --- a/benchmarks/RevDeps.hs +++ b/benchmarks/RevDeps.hs @@ -62,7 +62,7 @@ main :: IO () main = do packs :: Vector.Vector (Package TestPackage) <- randomPacks globalStdGen 20000 mempty let idx = PackageIndex.fromList $ map packToPkgInfo (Vector.toList packs) - Right revs <- pure $ constructReverseIndex idx + let revs = constructReverseIndex idx let numPacks = length packs defaultMain $ (:[]) $ @@ -70,7 +70,7 @@ main = do flip nfAppIO revs $ \revs' -> do select <- uniformRM (0, numPacks - 1) globalStdGen -- TODO why are there so many transitive deps? - length <$> + pure $ length $ getDependenciesFlat (packageName $ packToPkgInfo (packs Vector.! select)) revs' diff --git a/datafiles/templates/Html/maintain.html.st b/datafiles/templates/Html/maintain.html.st index 2a39e0cdc..256e69be1 100644 --- a/datafiles/templates/Html/maintain.html.st +++ b/datafiles/templates/Html/maintain.html.st @@ -48,7 +48,7 @@ package after its been released.
Test settings
If your package contains tests that can't run on hackage, you can disable them here. -

$versions:{pkgid|$pkgid$}; separator=", "$

+

$versions:{pkgid|$pkgid$}; separator=", "$

Trigger rebuild
diff --git a/src/Distribution/Server/Features/Html.hs b/src/Distribution/Server/Features/Html.hs index 21ab43c25..694093dc5 100644 --- a/src/Distribution/Server/Features/Html.hs +++ b/src/Distribution/Server/Features/Html.hs @@ -232,7 +232,7 @@ htmlFeature :: ServerEnv -> AsyncCache Response -> AsyncCache Response -> Templates - -> RecentPackagesFeature + -> RecentPackagesFeature -> (HtmlFeature, IO Response, IO Response) htmlFeature env@ServerEnv{..} @@ -526,7 +526,7 @@ mkHtmlCore ServerEnv{serverBaseURI, serverBlobStore} } ] - readParamWithDefaultAndValid :: (Read a, HasRqData m, Monad m, Functor m, Alternative m) => + readParamWithDefaultAndValid :: (Read a, HasRqData m, Monad m, Functor m, Alternative m) => a -> (a -> Bool) -> String -> m a readParamWithDefaultAndValid n f queryParam = do m <- optional (look queryParam) @@ -550,7 +550,7 @@ mkHtmlCore ServerEnv{serverBaseURI, serverBlobStore} pageSize <- lookupPageSize 20 let conf = Paging.createConf page pageSize recentPackages - + return . toResponse $ Pages.recentPage conf users recentPackages serveRecentRSS :: DynamicPath -> ServerPartE Response @@ -560,9 +560,9 @@ mkHtmlCore ServerEnv{serverBaseURI, serverBlobStore} page <- lookupPage 1 pageSize <- lookupPageSize 20 now <- liftIO getCurrentTime - + let conf = Paging.createConf page pageSize recentPackages - + return . toResponse $ Pages.recentFeed conf users serverBaseURI now recentPackages serveRevisionPage :: DynamicPath -> ServerPartE Response @@ -571,7 +571,7 @@ mkHtmlCore ServerEnv{serverBaseURI, serverBlobStore} users <- queryGetUserDb page <- lookupPage 1 pageSize <- lookupPageSize 40 - + let conf = Paging.createConf page pageSize revisions return . toResponse $ Pages.revisionsPage conf users revisions @@ -583,7 +583,7 @@ mkHtmlCore ServerEnv{serverBaseURI, serverBlobStore} page <- lookupPage 1 pageSize <- lookupPageSize 40 now <- liftIO getCurrentTime - + let conf = Paging.createConf page pageSize revisions return . toResponse $ Pages.recentRevisionsFeed conf users serverBaseURI now revisions @@ -614,7 +614,7 @@ mkHtmlCore ServerEnv{serverBaseURI, serverBlobStore} serveGraphJSON :: DynamicPath -> ServerPartE Response serveGraphJSON _ = do - graph <- revJSON + graph <- liftIO revJSON --TODO: use proper type for graph with ETag cacheControl [Public, maxAgeMinutes 30] (etagFromHash graph) ok . toResponse $ graph @@ -2178,7 +2178,7 @@ mkHtmlReverse HtmlUtilities{..} let pkgname = pkgName pkg pkgids <- lookupPackageName pkgname revCount <- revPackageStats pkgname - versions <- revForEachVersion pkgname + versions <- liftIO $ revForEachVersion pkgname return $ toResponse $ Resource.XHtml $ hackagePage (display pkgname ++ " - Reverse dependency statistics") $ reverseVerboseRender pkgname (map packageVersion pkgids) (corePackageIdUri "") revCount versions diff --git a/src/Distribution/Server/Features/ReverseDependencies.hs b/src/Distribution/Server/Features/ReverseDependencies.hs index 1a226b2c1..bff4c7f8e 100644 --- a/src/Distribution/Server/Features/ReverseDependencies.hs +++ b/src/Distribution/Server/Features/ReverseDependencies.hs @@ -21,13 +21,12 @@ import Distribution.Package import Distribution.Text (display) import Distribution.Version (Version) -import Control.Monad.Catch (MonadThrow, MonadCatch) import Data.Aeson import Data.ByteString.Lazy (ByteString) import Data.Containers.ListUtils (nubOrd) import Data.List (mapAccumL, sortOn) import qualified Data.List.NonEmpty as NE -import Data.Maybe (catMaybes, fromJust) +import Data.Maybe (catMaybes, mapMaybe, fromMaybe) import Data.Function (fix) import qualified Data.Bimap as Bimap import qualified Data.Array as Arr @@ -44,18 +43,18 @@ data ReverseFeature = ReverseFeature { reverseHook :: Hook [NE.NonEmpty PkgInfo] (), - queryReverseDeps :: forall m. (MonadIO m, MonadCatch m) => PackageName -> m ([PackageName], [PackageName]), - revPackageId :: forall m. (MonadCatch m, MonadIO m) => PackageId -> m ReverseDisplay, - revPackageName :: forall m. (MonadIO m, MonadCatch m) => PackageName -> m ReverseDisplay, - renderReverseRecent :: forall m. (MonadIO m, MonadCatch m) => PackageName -> ReverseDisplay -> m ReversePageRender, - renderReverseOld :: forall m. (MonadIO m, MonadCatch m) => PackageName -> ReverseDisplay -> m ReversePageRender, - revPackageFlat :: forall m. (MonadIO m, MonadCatch m) => PackageName -> m [(PackageName, Int)], - revDirectCount :: forall m. (MonadIO m, MonadCatch m) => PackageName -> m Int, - revPackageStats :: forall m. (MonadIO m, MonadCatch m) => PackageName -> m ReverseCount, - revCountForAllPackages :: forall m. (MonadIO m, MonadCatch m) => m [(PackageName, ReverseCount)], - revJSON :: forall m. (MonadIO m, MonadThrow m) => m ByteString, + queryReverseDeps :: forall m. MonadIO m => PackageName -> m ([PackageName], [PackageName]), + revPackageId :: forall m. MonadIO m => PackageId -> m ReverseDisplay, + revPackageName :: forall m. MonadIO m => PackageName -> m ReverseDisplay, + renderReverseRecent :: forall m. MonadIO m => PackageName -> ReverseDisplay -> m ReversePageRender, + renderReverseOld :: forall m. MonadIO m => PackageName -> ReverseDisplay -> m ReversePageRender, + revPackageFlat :: forall m. MonadIO m => PackageName -> m [(PackageName, Int)], + revDirectCount :: forall m. MonadIO m => PackageName -> m Int, + revPackageStats :: forall m. MonadIO m => PackageName -> m ReverseCount, + revCountForAllPackages :: forall m. MonadIO m => m [(PackageName, ReverseCount)], + revJSON :: IO ByteString, revDisplayInfo :: forall m. MonadIO m => m VersionIndex, - revForEachVersion :: forall m. (MonadIO m, MonadThrow m) => PackageName -> m (Map.Map Version (Set PackageIdentifier)) + revForEachVersion :: PackageName -> IO (Map.Map Version (Set PackageIdentifier)) } instance IsHackageFeature ReverseFeature where @@ -86,7 +85,7 @@ initReverseFeature _ = do return $ \CoreFeature{queryGetPackageIndex,packageChangeHook} VersionsFeature{queryGetPreferredVersions} -> do idx <- queryGetPackageIndex - memState <- newMemStateWHNF =<< constructReverseIndex idx + memState <- newMemStateWHNF $ constructReverseIndex idx let feature = reverseFeature queryGetPackageIndex queryGetPreferredVersions memState updateReverse @@ -95,9 +94,7 @@ initReverseFeature _ = do Nothing -> return () --PackageRemoveHook Just pkginfo -> do index <- queryGetPackageIndex - r <- readMemState memState - added <- addPackage index (packageName pkgid) (getDepNames pkginfo) r - writeMemState memState added + modifyMemState memState $ addPackage index (packageName pkgid) (getDepNames pkginfo) runHook_ updateReverse [pure pkginfo] return feature @@ -179,29 +176,29 @@ reverseFeature queryGetPackageIndex queryReverseIndex :: MonadIO m => m ReverseIndex queryReverseIndex = readMemState reverseMemState - queryReverseDeps :: (MonadIO m, MonadCatch m) => PackageName -> m ([PackageName], [PackageName]) + queryReverseDeps :: MonadIO m => PackageName -> m ([PackageName], [PackageName]) queryReverseDeps pkgname = do ms <- readMemState reverseMemState - rdeps <- getDependencies pkgname ms - rdepsall <- getDependenciesFlat pkgname ms - let indirect = Set.difference rdepsall rdeps - return (Set.toList rdeps, Set.toList indirect) + let rdeps = getDependencies pkgname ms + rdepsall = getDependenciesFlat pkgname ms + indirect = Set.difference rdepsall rdeps + pure (Set.toList rdeps, Set.toList indirect) - revPackageId :: (MonadCatch m, MonadIO m) => PackageId -> m ReverseDisplay + revPackageId :: MonadIO m => PackageId -> m ReverseDisplay revPackageId pkgid = do dispInfo <- revDisplayInfo pkgIndex <- liftIO queryGetPackageIndex revs <- queryReverseIndex - perVersionReverse dispInfo pkgIndex revs pkgid + pure $ perVersionReverse dispInfo pkgIndex revs pkgid - revPackageName :: (MonadIO m, MonadCatch m) => PackageName -> m ReverseDisplay + revPackageName :: MonadIO m => PackageName -> m ReverseDisplay revPackageName pkgname = do dispInfo <- revDisplayInfo pkgIndex <- liftIO queryGetPackageIndex revs <- queryReverseIndex - perPackageReverse dispInfo pkgIndex revs pkgname + pure $ perPackageReverse dispInfo pkgIndex revs pkgname - revJSON :: (MonadIO m, MonadThrow m) => m ByteString + revJSON :: IO ByteString revJSON = do ReverseIndex revdeps nodemap _depmap <- queryReverseIndex let assoc = takeWhile (\(a,_) -> a < Bimap.size nodemap) $ Arr.assocs . Gr.transposeG $ revdeps @@ -216,7 +213,7 @@ reverseFeature queryGetPackageIndex prefs <- liftIO queryGetPreferredVersions return $ getDisplayInfo prefs pkgIndex - renderReverseWith :: (MonadIO m, MonadCatch m) => PackageName -> ReverseDisplay -> (Maybe VersionStatus -> Bool) -> m ReversePageRender + renderReverseWith :: MonadIO m => PackageName -> ReverseDisplay -> (Maybe VersionStatus -> Bool) -> m ReversePageRender renderReverseWith pkg rev filterFunc = do let rev' = map fst $ Map.toList rev directCounts <- mapM revDirectCount (pkg:rev') @@ -224,19 +221,19 @@ reverseFeature queryGetPackageIndex toRender (i, i') (pkgname, (version, status)) = if filterFunc status then (,) (i+1, i') $ Just ReverseRender { rendRevPkg = PackageIdentifier pkgname version, rendRevStatus = status, - rendRevCount = fromJust $ lookup pkgname counts + rendRevCount = fromMaybe 0 $ lookup pkgname counts } else (,) (i, i'+1) Nothing (res, rlist) = mapAccumL toRender (0, 0) (Map.toList rev) - pkgCount = fromJust $ lookup pkg counts + pkgCount = fromMaybe 0 $ lookup pkg counts return $ ReversePageRender (catMaybes rlist) res pkgCount - renderReverseRecent :: (MonadIO m, MonadCatch m) => PackageName -> ReverseDisplay -> m ReversePageRender + renderReverseRecent :: MonadIO m => PackageName -> ReverseDisplay -> m ReversePageRender renderReverseRecent pkg rev = renderReverseWith pkg rev $ \status -> case status of Just DeprecatedVersion -> False Nothing -> False _ -> True - renderReverseOld :: (MonadIO m, MonadCatch m) => PackageName -> ReverseDisplay -> m ReversePageRender + renderReverseOld :: MonadIO m => PackageName -> ReverseDisplay -> m ReversePageRender renderReverseOld pkg rev = renderReverseWith pkg rev $ \status -> case status of Just DeprecatedVersion -> True Nothing -> True @@ -244,22 +241,20 @@ reverseFeature queryGetPackageIndex -- -- This could also differentiate between direct and indirect dependencies -- -- with a bit more calculation. - revPackageFlat :: (MonadIO m, MonadCatch m) => PackageName -> m [(PackageName, Int)] + revPackageFlat :: MonadIO m => PackageName -> m [(PackageName, Int)] revPackageFlat pkgname = do memState <- readMemState reverseMemState - deps <- getDependenciesFlat pkgname memState - let depList = Set.toList deps - counts <- mapM (`getTotalCount` memState) depList - return $ zip depList counts + let depList = Set.toList $ getDependenciesFlat pkgname memState + pure $ map (\d -> (d, getTotalCount d memState)) depList - revPackageStats :: (MonadIO m, MonadCatch m) => PackageName -> m ReverseCount + revPackageStats :: MonadIO m => PackageName -> m ReverseCount revPackageStats pkgname = do - (direct, transitive) <- getReverseCount pkgname =<< readMemState reverseMemState + (direct, transitive) <- getReverseCount pkgname <$> readMemState reverseMemState return $ ReverseCount direct transitive - revDirectCount :: (MonadIO m, MonadCatch m) => PackageName -> m Int + revDirectCount :: MonadIO m => PackageName -> m Int revDirectCount pkgname = do - getDirectCount pkgname =<< readMemState reverseMemState + getDirectCount pkgname <$> readMemState reverseMemState -- This returns a list of (package name, direct dependencies, flat dependencies) -- for all packages. An interesting fact: it even does so for packages which @@ -270,24 +265,26 @@ reverseFeature queryGetPackageIndex -- broken packages. -- -- The returned list is sorted ascendingly on directCount (see ReverseCount). - revCountForAllPackages :: (MonadIO m, MonadCatch m) => m [(PackageName, ReverseCount)] + revCountForAllPackages :: MonadIO m => m [(PackageName, ReverseCount)] revCountForAllPackages = do index <- liftIO queryGetPackageIndex let pkgnames = packageNames index counts <- mapM revPackageStats pkgnames return . sortOn (directCount . snd) $ zip pkgnames counts - revForEachVersion :: (MonadThrow m, MonadIO m) => PackageName -> m (Map.Map Version (Set PackageIdentifier)) + revForEachVersion :: PackageName -> IO (Map.Map Version (Set PackageIdentifier)) revForEachVersion pkg = do - ReverseIndex revs nodemap depmap <- readMemState reverseMemState - index <- liftIO queryGetPackageIndex - nodeid <- Bimap.lookup pkg nodemap - revDepNames <- mapM (`Bimap.lookupR` nodemap) (Set.toList $ suc revs nodeid) - let -- The key is the version of 'pkg', and the values are specific + ReverseIndex revs nodemap depmap <- readMemState reverseMemState + index <- queryGetPackageIndex + let revDepNames :: [PackageName] + revDepNames = case Bimap.lookup pkg nodemap of + Nothing -> [] + Just nodeid -> mapMaybe (`Bimap.lookupR` nodemap) (Set.toList $ suc revs nodeid) + let -- The key is the version of 'pkg', and the values are specific -- package versions that accept this version of pkg specified in the key revDepVersions :: [(Version, Set PackageIdentifier)] revDepVersions = do x <- nubOrd revDepNames pkginfo <- PackageIndex.lookupPackageName index pkg pure (packageVersion pkginfo, dependsOnPkg index (packageId pkginfo) x depmap) - pure $ Map.fromListWith Set.union revDepVersions + pure $ Map.fromListWith Set.union revDepVersions diff --git a/src/Distribution/Server/Features/ReverseDependencies/State.hs b/src/Distribution/Server/Features/ReverseDependencies/State.hs index e4f9a9632..b66c65fdf 100644 --- a/src/Distribution/Server/Features/ReverseDependencies/State.hs +++ b/src/Distribution/Server/Features/ReverseDependencies/State.hs @@ -29,9 +29,6 @@ module Distribution.Server.Features.ReverseDependencies.State import Prelude hiding (lookup) import Control.Arrow ((&&&)) -import Control.Monad (forM) -import Control.Monad.Catch -import Control.Monad.Reader (MonadIO) import qualified Data.Array as Arr ((!), assocs, accumArray) import Data.Bimap (Bimap, lookup, lookupR) import qualified Data.Bimap as Bimap @@ -39,7 +36,7 @@ import Data.Containers.ListUtils (nubOrd) import Data.List (union) import Data.Map (Map) import qualified Data.Map as Map -import Data.Maybe (catMaybes, mapMaybe, maybeToList) +import Data.Maybe (mapMaybe, maybeToList) import qualified Data.Set as Set import Data.Set (Set, fromList, toList, delete) import Data.Typeable (Typeable) @@ -76,52 +73,43 @@ instance MemSize Dependency where instance MemSize ReverseIndex where memSize (ReverseIndex a b c) = memSize3 a b c -constructReverseIndex :: MonadCatch m => PackageIndex PkgInfo -> m ReverseIndex -constructReverseIndex index = do +constructReverseIndex :: PackageIndex PkgInfo -> ReverseIndex +constructReverseIndex index = let nodePkgMap = foldr (uncurry Bimap.insert) Bimap.empty $ zip (PackageIndex.allPackageNames index) [0..] - (revs, dependencies) <- constructRevDeps index nodePkgMap - pure $ - ReverseIndex + (revs, dependencies) = constructRevDeps index nodePkgMap + in ReverseIndex { reverseDependencies = revs , packageNodeIdMap = nodePkgMap , deps = dependencies } -addPackage :: (MonadCatch m, MonadIO m) => PackageIndex PkgInfo -> PackageName -> [PackageName] - -> ReverseIndex -> m ReverseIndex -addPackage index pkgname dependencies ri@(ReverseIndex revs nodemap pkgIdToDeps) = do - let - npm = Bimap.tryInsert pkgname (Bimap.size nodemap) nodemap - new :: [(Int, [Int])] <- - forM dependencies $ \d -> - (,) <$> lookup d npm <*> fmap (:[]) (lookup pkgname npm) - let rd = insEdges (Bimap.size npm) new revs +addPackage :: PackageIndex PkgInfo -> PackageName -> [PackageName] + -> ReverseIndex -> ReverseIndex +addPackage index pkgname dependencies (ReverseIndex revs nodemap pkgIdToDeps) = + let npm = Bimap.tryInsert pkgname (Bimap.size nodemap) nodemap + pn = (:[]) <$> lookup pkgname npm + new :: [(Int, [Int])] + new = mapMaybe (\d -> (,) <$> lookup d npm <*> pn) dependencies + rd = insEdges (Bimap.size npm) new revs pkginfos = PackageIndex.lookupPackageName index pkgname newPackageDepMap = Map.fromList $ map (packageId &&& getDeps) pkginfos - pure - ri + in ReverseIndex { reverseDependencies = rd , packageNodeIdMap = npm , deps = Map.union newPackageDepMap pkgIdToDeps } -constructRevDeps :: forall m. MonadCatch m => PackageIndex PkgInfo -> Bimap PackageName NodeId -> m (RevDeps, Map PackageIdentifier [Dependency]) -constructRevDeps index nodemap = do +constructRevDeps :: PackageIndex PkgInfo -> Bimap PackageName NodeId -> (RevDeps, Map PackageIdentifier [Dependency]) +constructRevDeps index nodemap = let allPackages :: [PkgInfo] allPackages = concat $ PackageIndex.allPackagesByName index - nodeIdsOfDependencies :: PkgInfo -> m [(NodeId, NodeId)] - nodeIdsOfDependencies pkg = catMaybes <$> mapM findNodesIfPresent (getDepNames pkg) - where - findNodesIfPresent :: PackageName -> m (Maybe (NodeId, NodeId)) - findNodesIfPresent dep = do - eitherErrOrFound :: Either SomeException (NodeId, NodeId) <- - try $ (,) <$> lookup dep nodemap <*> lookup (packageName pkg) nodemap - pure $ either (const Nothing) Just eitherErrOrFound - -- This will mix dependencies of different versions of the same package, but that is intended. - edges <- traverse nodeIdsOfDependencies allPackages - let dependencies = Map.fromList $ map (packageId &&& getDeps) allPackages - - pure (Gr.buildG (0, Bimap.size nodemap) (nubOrd $ concat edges) + nodeIdsOfDependencies :: PkgInfo -> [(NodeId, NodeId)] + nodeIdsOfDependencies pkg = mapMaybe (\dep -> (,) <$> lookup dep nodemap <*> lookup (packageName pkg) nodemap) (getDepNames pkg) + -- This will mix dependencies of different versions of the same package, but that is intended. + edges = map nodeIdsOfDependencies allPackages + dependencies = Map.fromList $ map (packageId &&& getDeps) allPackages + + in (Gr.buildG (0, Bimap.size nodemap) (nubOrd $ concat edges) , dependencies ) @@ -170,21 +158,22 @@ type ReverseDisplay = Map PackageName (Version, Maybe VersionStatus) type VersionIndex = (PackageName -> (PreferredInfo, [Version])) -perPackageReverse :: MonadCatch m => (PackageName -> (PreferredInfo, [Version])) -> PackageIndex PkgInfo -> ReverseIndex -> PackageName -> m (Map PackageName (Version, Maybe VersionStatus)) -perPackageReverse indexFunc index revdeps pkg = do +perPackageReverse :: (PackageName -> (PreferredInfo, [Version])) -> PackageIndex PkgInfo -> ReverseIndex -> PackageName -> Map PackageName (Version, Maybe VersionStatus) +perPackageReverse indexFunc index revdeps pkg = let pkgids = (packageVersion. packageId) <$> PackageIndex.lookupPackageName index pkg - let best :: PackageId + best :: PackageId best = PackageIdentifier pkg (maximum pkgids) - perVersionReverse indexFunc index revdeps best - -perVersionReverse :: MonadCatch m => (PackageName -> (PreferredInfo, [Version])) -> PackageIndex PkgInfo -> ReverseIndex -> PackageId -> m (Map PackageName (Version, Maybe VersionStatus)) -perVersionReverse indexFunc index (ReverseIndex revs nodemap dependencies) pkg = do - found <- lookup (packageName pkg) nodemap - -- this will be too much, since we are throwing away the specific version - revDepNames :: Set PackageName <- fromList <$> mapM (`lookupR` nodemap) (toList $ suc revs found) - let packagemap :: Map PackageName (Set Version) - packagemap = Map.fromList $ map (\x -> (x, Set.map packageVersion $ dependsOnPkg index pkg x dependencies)) (toList revDepNames) - pure $ constructReverseDisplay indexFunc packagemap + in perVersionReverse indexFunc index revdeps best + +perVersionReverse :: (PackageName -> (PreferredInfo, [Version])) -> PackageIndex PkgInfo -> ReverseIndex -> PackageId -> Map PackageName (Version, Maybe VersionStatus) +perVersionReverse indexFunc index (ReverseIndex revs nodemap dependencies) pkg = case lookup (packageName pkg) nodemap of + Nothing -> Map.empty + Just found -> + -- this will be too much, since we are throwing away the specific version + let revDepNames = mapMaybe (`lookupR` nodemap) (toList $ suc revs found) + packagemap :: Map PackageName (Set Version) + packagemap = Map.fromList $ map (\x -> (x, Set.map packageVersion $ dependsOnPkg index pkg x dependencies)) revDepNames + in constructReverseDisplay indexFunc packagemap constructReverseDisplay :: (PackageName -> (PreferredInfo, [Version])) -> Map PackageName (Set Version) -> Map PackageName (Version, Maybe VersionStatus) constructReverseDisplay indexFunc = @@ -207,52 +196,38 @@ insEdges nodesize edges revdeps = Arr.accumArray union [] (0, nodesize) (edges + -------------------------------------- -getDependencies :: MonadCatch m => PackageName -> ReverseIndex -> m (Set PackageName) -getDependencies pkg revs = - names revs =<< getDependenciesRaw pkg revs +getDependencies :: PackageName -> ReverseIndex -> Set PackageName +getDependencies pkg revs = names revs $ getDependenciesRaw pkg revs -getDependenciesRaw :: MonadCatch m => PackageName -> ReverseIndex -> m (Set NodeId) -getDependenciesRaw pkg (ReverseIndex revdeps nodemap _) = do - enodeid <- try (lookup pkg nodemap) - onRight enodeid $ \nodeid -> - nodeid `delete` suc revdeps nodeid +getDependenciesRaw :: PackageName -> ReverseIndex -> Set NodeId +getDependenciesRaw pkg (ReverseIndex revdeps nodemap _) = + case lookup pkg nodemap of + Nothing -> mempty + Just nodeid -> delete nodeid (suc revdeps nodeid) -- | The flat/total/transitive/indirect reverse dependencies are all the packages that depend on something that depends on the given 'pkg' -getDependenciesFlat :: forall m. MonadCatch m => PackageName -> ReverseIndex -> m (Set PackageName) -getDependenciesFlat pkg revs = - names revs =<< getDependenciesFlatRaw pkg revs +getDependenciesFlat :: PackageName -> ReverseIndex -> Set PackageName +getDependenciesFlat pkg revs = names revs $ getDependenciesFlatRaw pkg revs -getDependenciesFlatRaw :: forall m. MonadCatch m => PackageName -> ReverseIndex -> m (Set NodeId) +getDependenciesFlatRaw :: PackageName -> ReverseIndex -> Set NodeId getDependenciesFlatRaw pkg (ReverseIndex revdeps nodemap _) = do - enodeid <- try (lookup pkg nodemap) - onRight enodeid $ \nodeid -> - nodeid `delete` fromList (Gr.reachable revdeps nodeid) + case lookup pkg nodemap of + Nothing -> mempty + Just nodeid -> delete nodeid $ fromList (Gr.reachable revdeps nodeid) -- | The direct dependencies depend on the given 'pkg' directly, i.e. not transitively -getDirectCount :: MonadCatch m => PackageName -> ReverseIndex -> m Int -getDirectCount pkg revs = do - length <$> getDependenciesRaw pkg revs +getDirectCount :: PackageName -> ReverseIndex -> Int +getDirectCount pkg revs = length $ getDependenciesRaw pkg revs -- | Given a set of NodeIds, look up the package names for all of them -names :: MonadThrow m => ReverseIndex -> Set NodeId -> m (Set PackageName) +names :: ReverseIndex -> Set NodeId -> Set PackageName names (ReverseIndex _ nodemap _) ids = do - fromList <$> mapM (`lookupR` nodemap) (toList ids) + fromList $ mapMaybe (`lookupR` nodemap) (toList ids) -onRight :: Monad m => Either SomeException t -> (t -> Set NodeId) -> m (Set NodeId) -onRight e fun = do - case e of - Left (_ :: SomeException) -> do - pure mempty - Right nodeid -> - pure $ fun nodeid -- | The flat/total/transitive/indirect dependency count is the amount of package names that depend transitively on the given 'pkg' -getTotalCount :: MonadCatch m => PackageName -> ReverseIndex -> m Int -getTotalCount pkg revs = do - length <$> getDependenciesFlatRaw pkg revs - -getReverseCount :: MonadCatch m => PackageName -> ReverseIndex -> m (Int, Int) -getReverseCount pkg revs = do - direct <- getDirectCount pkg revs - total <- getTotalCount pkg revs - pure (direct, total) +getTotalCount :: PackageName -> ReverseIndex -> Int +getTotalCount pkg revs = length $ getDependenciesFlatRaw pkg revs + +getReverseCount :: PackageName -> ReverseIndex -> (Int, Int) +getReverseCount pkg revs = (getDirectCount pkg revs, getTotalCount pkg revs) diff --git a/tests/ReverseDependenciesTest.hs b/tests/ReverseDependenciesTest.hs index 6c2bbf94d..3cf3b42dc 100644 --- a/tests/ReverseDependenciesTest.hs +++ b/tests/ReverseDependenciesTest.hs @@ -1,13 +1,10 @@ {-# LANGUAGE OverloadedStrings, NamedFieldPuns, TypeApplications, ScopedTypeVariables #-} module Main where -import Control.Monad (foldM) -import Control.Monad.Catch (MonadCatch, SomeException, catch) -import Control.Monad.IO.Class (MonadIO, liftIO) import qualified Data.Array as Arr import qualified Data.Bimap as Bimap import Data.Foldable (for_) -import Data.List (partition) +import Data.List (partition, foldl') import qualified Data.Map as Map import qualified Data.Set as Set @@ -26,7 +23,7 @@ import Test.Tasty.HUnit import qualified Hedgehog.Range as Range import qualified Hedgehog.Gen as Gen -import Hedgehog ((===), Group(Group), MonadGen, MonadTest, Property, PropertyT, checkSequential, failure, footnoteShow, forAll, property) +import Hedgehog ((===), Group(Group), MonadGen, Property, PropertyT, checkSequential, forAll, property) import RevDepCommon (Package(..), TestPackage(..), mkPackage, packToPkgInfo) @@ -51,7 +48,7 @@ mkRevFeat pkgs = do , migratedEphemeralPrefs = False } updateReverse <- newHook - constructed <- constructReverseIndex idx + let constructed = constructReverseIndex idx memState <- newMemStateWHNF constructed pure $ reverseFeature @@ -151,8 +148,8 @@ prop_constructRevDeps :: Property prop_constructRevDeps = property $ do packs <- genPacks let idx = PackageIndex.fromList $ map packToPkgInfo packs - ReverseIndex foldedRevDeps foldedMap foldedDeps <- foldM (packageFolder @_ @TestPackage idx) emptyReverseIndex packs - Right (ReverseIndex constructedRevDeps constructedMap constructedDeps) <- pure $ constructReverseIndex idx + let ReverseIndex foldedRevDeps foldedMap foldedDeps = foldl' (packageFolder idx) emptyReverseIndex packs + let (ReverseIndex constructedRevDeps constructedMap constructedDeps) = constructReverseIndex idx for_ (PackageIndex.allPackageNames idx) $ \name -> do foundFolded :: Int <- Bimap.lookup name foldedMap foundConstructed :: Int <- Bimap.lookup name constructedMap @@ -171,24 +168,18 @@ prop_statsEqualsDeps :: Property prop_statsEqualsDeps = property $ do packs <- genPacks let packages = map packToPkgInfo packs - Right revs <- pure $ constructReverseIndex $ PackageIndex.fromList packages + let revs = constructReverseIndex $ PackageIndex.fromList packages pkginfo <- forAll $ Gen.element packages let name = packageName pkginfo - directSet <- getDependenciesRaw name revs - totalSet <- getDependenciesFlatRaw name revs - directNames <- getDependencies name revs - totalNames <- getDependenciesFlat name revs + let directSet = getDependenciesRaw name revs + totalSet = getDependenciesFlatRaw name revs + directNames = getDependencies name revs + totalNames = getDependenciesFlat name revs length directSet === length directNames length totalSet === length totalNames -packageFolder :: (MonadCatch m, MonadIO m, MonadTest m, Show b) => PackageIndex PkgInfo -> ReverseIndex -> Package b -> m ReverseIndex -packageFolder index revindex pkg@(Package name _version deps) = - catch (liftIO $ addPackage index (mkPackageName $ show name) (map (mkPackageName . show) deps) revindex) - $ \(e :: SomeException) -> do - footnoteShow pkg - footnoteShow index - footnoteShow e - failure +packageFolder :: Show b => PackageIndex PkgInfo -> ReverseIndex -> Package b -> ReverseIndex +packageFolder index revindex (Package name _version deps) = addPackage index (mkPackageName $ show name) (map (mkPackageName . show) deps) revindex genPackage :: forall m b. (MonadGen m, Enum b, Bounded b, Ord b) => b -> [Package b] -> m (Package b)