packages feed

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

module Hix.Managed.Data.Mutable (
  MutableDep (MutableDep),
  MutableDeps,
  unsafeMutableDep,
  depName,
  isMutableDep,
  validate,
  MutableVersions,
  MutableBounds,
  MutableRanges,
  LocalRanges,
  mutRestrictKeys,
  mutLookup,
  mutReplace,
  mutReplaceTargets,
  mutUpdate,
  mutUpdateTargets,
  classifyPackageDep,
  mutRelax,
  mutUpdatePartial,
  mutReplacePartial,
  addBuildVersions,
  mutFromSet,
  mutRelaxVersions,
  mutNonTargets,
  forTargets,
) where

import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey)
import qualified Data.Set as Set
import Distribution.Pretty (Pretty (pretty))
import Exon (ToSegment (toSegment))
import GHC.Exts (IsList)

import Hix.Class.EncodeNix (EncodeNix (encodeNix), EncodeNixKey)
import Hix.Class.Map (
  LookupMaybe,
  NLookup,
  NMap,
  nAmend,
  nFromKeys,
  nMap,
  nMapKeys,
  nPartitionByKey,
  nPretty,
  nPrettyWith,
  nRestrictKeys,
  nTransformMaybe,
  (!!),
  )
import qualified Hix.Data.Dep
import Hix.Data.Dep (Dep (Dep))
import Hix.Data.PackageName (LocalPackage (LocalPackage), PackageName)
import Hix.Data.Version (Version, VersionRange, Versions)
import Hix.Data.VersionBounds (VersionBounds)
import Hix.Managed.Data.Packages (Deps, Packages)
import Hix.Managed.Data.Targets (Targets)
import qualified Hix.Managed.Targets as Targets
import Hix.Managed.Targets (onlyTargets, overTargets)
import Hix.Maybe (justIf)

newtype MutableDep =
  UnsafeMutableDep PackageName
  deriving stock (Eq, Show)
  deriving newtype (Ord, ToJSON, ToJSONKey, Pretty, EncodeNixKey, FromJSON, FromJSONKey)

pattern MutableDep :: PackageName -> MutableDep
pattern MutableDep name <- UnsafeMutableDep name

{-# complete MutableDep #-}

unsafeMutableDep :: PackageName -> MutableDep
unsafeMutableDep = UnsafeMutableDep

depName :: MutableDep -> PackageName
depName (UnsafeMutableDep name) = name

isMutableDep :: Set MutableDep -> PackageName -> Bool
isMutableDep mut p = Set.member (UnsafeMutableDep p) mut

validate :: Set MutableDep -> PackageName -> Maybe MutableDep
validate pool candidate =
  justIf (isMutableDep pool candidate) (UnsafeMutableDep candidate)

instance IsString a => ToSegment MutableDep a where
  toSegment (UnsafeMutableDep name) = toSegment name

newtype MutableDeps a =
  MutableDeps (Map MutableDep a)
  deriving stock (Eq, Show, Generic)
  deriving newtype (Semigroup, Monoid, EncodeNix)

instance NMap (MutableDeps a) MutableDep a LookupMaybe where

instance Pretty a => Pretty (MutableDeps a) where
  pretty = nPretty

newtype MutableVersions =
  MutableVersions (Map MutableDep (Maybe Version))
  deriving stock (Eq, Show, Generic)
  deriving newtype (Semigroup, Monoid, IsList)

instance NMap MutableVersions MutableDep (Maybe Version) LookupMaybe where

instance Pretty MutableVersions where
  pretty = nPrettyWith (maybe "[missing]" pretty)

instance EncodeNix MutableVersions where
  encodeNix = encodeNix . mutRelaxVersions

newtype MutableBounds =
  MutableBounds (Map MutableDep VersionBounds)
  deriving stock (Eq, Show, Generic)
  deriving newtype (Semigroup, Monoid, IsList, EncodeNix, ToJSON)

instance NMap MutableBounds MutableDep VersionBounds LookupMaybe where

instance Pretty MutableBounds where
  pretty = nPretty

newtype MutableRanges =
  MutableRanges (Map MutableDep VersionRange)
  deriving stock (Eq, Show, Generic)
  deriving newtype (Semigroup, Monoid, IsList)

instance NMap MutableRanges MutableDep VersionRange LookupMaybe where

instance Pretty MutableRanges where
  pretty = nPretty

newtype LocalRanges =
  LocalRanges (Map LocalPackage VersionRange)
  deriving stock (Eq, Show, Generic)
  deriving newtype (Semigroup, Monoid, IsList)

instance NMap LocalRanges LocalPackage VersionRange LookupMaybe where

instance Pretty LocalRanges where
  pretty = nPretty

mutLookup ::
  NMap map MutableDep v sort =>
  NLookup sort MutableDep v l =>
  PackageName ->
  map ->
  l
mutLookup k m =
  m !! UnsafeMutableDep k

mutRestrictKeys ::
  NMap map MutableDep v sort =>
  Set PackageName ->
  map ->
  map
mutRestrictKeys keys =
  nRestrictKeys (Set.fromList (UnsafeMutableDep <$> Set.toList keys))

mutReplace ::
  NMap map MutableDep v sort =>
  map ->
  map ->
  map
mutReplace =
  nAmend \ new _ -> new

mutReplaceTargets ::
  NMap map MutableDep v sort =>
  Targets ->
  map ->
  Packages map ->
  Packages map
mutReplaceTargets targets new =
  overTargets targets (mutReplace new)

mutUpdate ::
  NMap map1 MutableDep v1 s1 =>
  NMap map2 MutableDep v2 s2 =>
  (v1 -> v2 -> v2) ->
  map1 ->
  map2 ->
  map2
mutUpdate =
  nAmend

mutUpdateTargets ::
  NMap map1 MutableDep v1 s1 =>
  NMap map2 MutableDep v2 s2 =>
  Targets ->
  (v1 -> v2 -> v2) ->
  map1 ->
  Packages map2 ->
  Packages map2
mutUpdateTargets targets f new =
  overTargets targets (mutUpdate f new)

mutRelax ::
  NMap map1 MutableDep v s1 =>
  NMap map2 PackageName v s2 =>
  map1 ->
  map2
mutRelax =
  nMapKeys depName

mutRelaxVersions ::
  MutableVersions ->
  Versions
mutRelaxVersions =
  nTransformMaybe \ dep -> fmap (depName dep,)

-- | Update a MutableDep map with a PackageName map, only where the original is defined.
mutUpdatePartial ::
  ∀ map1 map2 v1 v2 s1 s2 .
  NMap map1 PackageName v1 s1 =>
  NMap map2 MutableDep v2 s2 =>
  (v1 -> v2 -> v2) ->
  map1 ->
  map2 ->
  map2
mutUpdatePartial f map1 map2 =
  nAmend f (nMapKeys UnsafeMutableDep map1 :: MutableDeps v1) map2

-- | Replace entries in a MutableDep map with those from a PackageName map, only where the original is defined.
mutReplacePartial ::
  ∀ map1 map2 v1 s1 s2 .
  NMap map1 PackageName v1 s1 =>
  NMap map2 MutableDep v1 s2 =>
  map1 ->
  map2 ->
  map2
mutReplacePartial =
  mutUpdatePartial const

addBuildVersions :: Versions -> MutableVersions -> MutableVersions
addBuildVersions versions =
  mutReplacePartial (nMap Just versions :: Deps (Maybe Version))

classifyPackageDep :: Set LocalPackage -> Dep -> Either (LocalPackage, VersionRange) (MutableDep, VersionRange)
classifyPackageDep locals Dep {package, version}
  | Set.member localName locals
  = Left (localName, version)
  | otherwise
  = Right (UnsafeMutableDep package, version)
  where
    localName = LocalPackage package

mutFromSet ::
  NMap map MutableDep v sort =>
  Set MutableDep ->
  (MutableDep -> v) ->
  map
mutFromSet =
  nFromKeys

-- TODO remove
mutNonTargets ::
  Targets ->
  LocalRanges ->
  (MutableRanges, LocalRanges)
mutNonTargets targets =
  nPartitionByKey \case
    package | Targets.member package targets -> Right package
    LocalPackage package -> Left (UnsafeMutableDep package)

forTargets ::
  NMap map1 PackageName a sort1 =>
  NMap map2 MutableDep a sort2 =>
  Targets ->
  Packages map1 ->
  Packages map2
forTargets targets =
  onlyTargets targets . nMap transformOne
  where
    transformOne =
      nTransformMaybe \ package a ->
        justIf (not (Targets.member (LocalPackage package) targets)) (UnsafeMutableDep package, a)