packages feed

hix-0.9.0: lib/Hix/Managed/Data/Targets.hs

module Hix.Managed.Data.Targets (
  Targets (Targets),
  unsafeTargets,
  singleTarget,
  unsortedTargets,
  sortTargets,
  firstMTargets,
) where

import Data.Graph (Graph, Vertex, graphFromEdges, reverseTopSort)
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Distribution.Pretty (Pretty (pretty))

import Hix.Class.Map (nGet, nMap, nRestrictKeys)
import Hix.Data.PackageName (LocalPackage, PackageName, toLocalPackage)
import Hix.Managed.Data.Packages (Packages)
import Hix.Pretty (prettyL)

newtype Targets =
  UnsafeTargets [LocalPackage]
  deriving stock (Eq, Show)

pattern Targets :: [LocalPackage] -> Targets
pattern Targets pkgs <- UnsafeTargets pkgs

{-# complete Targets #-}

unsafeTargets :: [LocalPackage] -> Targets
unsafeTargets = UnsafeTargets

singleTarget :: LocalPackage -> Targets
singleTarget = UnsafeTargets . pure

instance IsString Targets where
  fromString = singleTarget . fromString

instance Pretty Targets where
  pretty (Targets ps) = prettyL ps

unsortedTargets :: Targets -> Set LocalPackage
unsortedTargets (Targets targets) = Set.fromList targets

graph ::
  Map LocalPackage [LocalPackage] ->
  (Graph, Vertex -> (LocalPackage, LocalPackage, [LocalPackage]), LocalPackage -> Maybe Vertex)
graph deps =
  graphFromEdges [(p, p, ds) | (p, ds) <- Map.toList deps]

onlyFrom :: Set LocalPackage -> [PackageName] -> [LocalPackage]
onlyFrom targets = mapMaybe (toLocalPackage targets)

sortTargets ::
  Packages [PackageName] ->
  [LocalPackage] ->
  Targets
sortTargets deps targets =
  UnsafeTargets (reverseTopSort g <&> \ v -> let (n, _, _) = get v in n)
  where
    (g, get, _) = graph (nGet simple)

    simple :: Packages [LocalPackage]
    simple = nMap (onlyFrom targetSet) (nRestrictKeys targetSet deps)

    targetSet = Set.fromList targets

-- | Run the computation for each target in topological order, aborting and returning the computation's result if it
-- meets the error condition.
-- If all computations succeed, return the success value.
firstMTargets ::
  Monad m =>
  -- | Success value.
  a ->
  -- | Error condition.
  (a -> Bool) ->
  -- | Computation.
  (LocalPackage -> m a) ->
  -- | Iteration sequence targets.
  Targets ->
  m a
firstMTargets success cond f (Targets targets) =
  foldr chain (pure success) targets
  where
    chain a z = do
      res <- f a
      if cond res
      then pure res
      else z