packages feed

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

module Hix.Managed.Data.Targets (
  Targets (Targets),
  unsafeTargets,
  getTargets,
  targetsSet,
  singleTarget,
  sortTargets,
  allMTargets,
  overTargets,
) where

import Data.Aeson (FromJSON, FromJSONKey)
import Data.Foldable.Extra (allM)
import Data.Graph (Graph, Vertex, graphFromEdges, reverseTopSort)
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Distribution.Pretty (Pretty)

import Hix.Class.EncodeNix (EncodeNixKey)
import Hix.Class.Map (nGet, nMap, nMapWithKey, nRestrictKeys)
import Hix.Data.PackageName (LocalPackage (LocalPackage))
import Hix.Managed.Data.Packages (Packages)

newtype EnvMember =
  EnvMember LocalPackage
  deriving stock (Eq, Show, Generic)
  deriving newtype (IsString, Ord, FromJSON, FromJSONKey, Pretty, EncodeNixKey)

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

getTargets :: Targets -> [LocalPackage]
getTargets (Targets pkgs) = pkgs

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

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

onlyFrom :: Set LocalPackage -> [LocalPackage] -> [LocalPackage]
onlyFrom targets deps =
  mapMaybe isTarget deps
  where
    isTarget = \case
      dep | Set.member dep targets -> Just dep
      _ -> Nothing

sortTargets ::
  Packages [LocalPackage] ->
  [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

allMTargets ::
  Monad m =>
  (LocalPackage -> m Bool) ->
  Targets ->
  m Bool
allMTargets f (Targets targets) =
  allM f targets

overTargets :: Targets -> (a -> a) -> Packages a -> Packages a
overTargets (targetsSet -> targets) f =
  nMapWithKey checked
  where
    checked package a
      | Set.member package targets
      = f a
      | otherwise
      = a