module Hix.Managed.Cabal.Mock.SourcePackage where

import qualified Data.Map.Strict as Map
import Distribution.Client.Types (PackageLocation (LocalTarballPackage), SourcePackageDb (..), UnresolvedSourcePackage)
import Distribution.PackageDescription (
  CondTree (..),
  Library (libBuildInfo),
  LibraryVisibility (LibraryVisibilityPublic),
  PackageDescription (..),
  emptyLibrary,
  emptyPackageDescription, BuildInfo (targetBuildDepends),
  )
import Distribution.Simple (Version)
import qualified Distribution.Solver.Types.PackageIndex as PackageIndex
import Distribution.Solver.Types.PackageIndex (PackageIndex)
import Distribution.Solver.Types.SourcePackage (SourcePackage (..))
import Distribution.Types.GenericPackageDescription (GenericPackageDescription (..), emptyGenericPackageDescription)
import Distribution.Types.Library (libVisibility)
import Exon (exon)

import Hix.Class.Map (nGet, nKeys, nMap, nTo1, nTransform, nVia, (!!))
import qualified Hix.Data.Dep as Dep
import Hix.Data.Dep (Dep)
import Hix.Data.Monad (M)
import qualified Hix.Data.PackageId as PackageId
import Hix.Data.PackageId (PackageId (PackageId))
import Hix.Data.PackageName (LocalPackage (LocalPackage), PackageName, localPackageName)
import Hix.Managed.Cabal.Data.SourcePackage (SourcePackageDeps, SourcePackageVersions, SourcePackages)
import qualified Hix.Managed.Data.ManagedPackage as ManagedPackage
import Hix.Managed.Data.ManagedPackage (ManagedPackage)
import Hix.Managed.Data.Packages (Packages)
import Hix.Monad (noteClient)

allDeps :: [Dep] -> SourcePackageDeps -> SourcePackageDeps
allDeps :: [Dep] -> SourcePackageDeps -> SourcePackageDeps
allDeps [Dep]
deps = (Map Version [Dep] -> Map Version [Dep])
-> SourcePackageDeps -> SourcePackageDeps
forall map1 k1 v1 s1 map2 k2 v2 s2.
(NMap map1 k1 v1 s1, NMap map2 k2 v2 s2) =>
(Map k1 v1 -> Map k2 v2) -> map1 -> map2
nVia (([Dep] -> [Dep]) -> Map Version [Dep] -> Map Version [Dep]
forall a b. (a -> b) -> Map Version a -> Map Version b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Dep]
deps ++))

allDep :: Dep -> SourcePackageDeps -> SourcePackageDeps
allDep :: Dep -> SourcePackageDeps -> SourcePackageDeps
allDep Dep
dep = (Map Version [Dep] -> Map Version [Dep])
-> SourcePackageDeps -> SourcePackageDeps
forall map1 k1 v1 s1 map2 k2 v2 s2.
(NMap map1 k1 v1 s1, NMap map2 k2 v2 s2) =>
(Map k1 v1 -> Map k2 v2) -> map1 -> map2
nVia (([Dep] -> [Dep]) -> Map Version [Dep] -> Map Version [Dep]
forall a b. (a -> b) -> Map Version a -> Map Version b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Dep
dep :))

sourcePackageVersions :: SourcePackages -> SourcePackageVersions
sourcePackageVersions :: SourcePackages -> SourcePackageVersions
sourcePackageVersions = (SourcePackageDeps -> [Version])
-> SourcePackages -> SourcePackageVersions
forall map1 k v1 sort1 map2 v2 sort2.
(NMap map1 k v1 sort1, NMap map2 k v2 sort2) =>
(v1 -> v2) -> map1 -> map2
nMap ([Version] -> [Version]
forall a. Ord a => [a] -> [a]
sort ([Version] -> [Version])
-> (SourcePackageDeps -> [Version])
-> SourcePackageDeps
-> [Version]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SourcePackageDeps -> [Version]
forall map k v sort. NMap map k v sort => map -> [k]
nKeys)

queryVersions :: SourcePackageVersions -> PackageName -> M [Version]
queryVersions :: SourcePackageVersions -> PackageName -> M [Version]
queryVersions SourcePackageVersions
packages PackageName
query = Text -> Maybe [Version] -> M [Version]
forall a. Text -> Maybe a -> M a
noteClient [exon|No such package in the source db: ##{query}|] (SourcePackageVersions
packages SourcePackageVersions -> PackageName -> Maybe [Version]
forall map k v sort l.
(NMap map k v sort, NLookup sort k v l) =>
map -> k -> l
!! PackageName
query)

queryPackages :: SourcePackages -> PackageName -> M [Version]
queryPackages :: SourcePackages -> PackageName -> M [Version]
queryPackages SourcePackages
packages =
  SourcePackageVersions -> PackageName -> M [Version]
queryVersions (SourcePackages -> SourcePackageVersions
sourcePackageVersions SourcePackages
packages)

queryVersionsLatest :: SourcePackageVersions -> PackageName -> M (Maybe Version)
queryVersionsLatest :: SourcePackageVersions -> PackageName -> M (Maybe Version)
queryVersionsLatest SourcePackageVersions
packages PackageName
query = [Version] -> Maybe Version
forall a. [a] -> Maybe a
last ([Version] -> Maybe Version) -> M [Version] -> M (Maybe Version)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SourcePackageVersions -> PackageName -> M [Version]
queryVersions SourcePackageVersions
packages PackageName
query

queryPackagesLatest :: SourcePackages -> PackageName -> M (Maybe Version)
queryPackagesLatest :: SourcePackages -> PackageName -> M (Maybe Version)
queryPackagesLatest SourcePackages
packages =
  SourcePackageVersions -> PackageName -> M (Maybe Version)
queryVersionsLatest SourcePackageVersions
versions
  where
    versions :: SourcePackageVersions
versions = SourcePackages -> SourcePackageVersions
sourcePackageVersions SourcePackages
packages

-- | This _must_ have the dependencies in both 'targetBuildDepends' and 'condTreeConstraints', otherwise they will be
-- ignored or deleted depending on what resolver params are used.
-- This is also evidenced by looking at a parsed Cabal file, see @CabalTest@.
mockSourcePackage :: PackageName -> Version -> [Dep] -> UnresolvedSourcePackage
mockSourcePackage :: PackageName -> Version -> [Dep] -> UnresolvedSourcePackage
mockSourcePackage PackageName
name Version
version [Dep]
deps =
  SourcePackage {
    srcpkgPackageId :: PackageId
srcpkgPackageId = PackageId
cabalId,
    srcpkgDescription :: GenericPackageDescription
srcpkgDescription = GenericPackageDescription
emptyGenericPackageDescription {
      packageDescription :: PackageDescription
packageDescription = PackageDescription
emptyPackageDescription {
        package :: PackageId
package = PackageId
cabalId
      },
      condLibrary :: Maybe (CondTree ConfVar [Dependency] Library)
condLibrary = CondTree ConfVar [Dependency] Library
-> Maybe (CondTree ConfVar [Dependency] Library)
forall a. a -> Maybe a
Just CondTree ConfVar [Dependency] Library
library
    },
    srcpkgSource :: PackageLocation (Maybe String)
srcpkgSource = String -> PackageLocation (Maybe String)
forall local. String -> PackageLocation local
LocalTarballPackage String
"/invalid",
    srcpkgDescrOverride :: PackageDescriptionOverride
srcpkgDescrOverride = PackageDescriptionOverride
forall a. Maybe a
Nothing
  }
  where
    library :: CondTree ConfVar [Dependency] Library
library =
      CondTree ConfVar [Dependency] Library
forall a. Monoid a => a
mempty {
        condTreeData :: Library
condTreeData = Library
emptyLibrary {
          libVisibility :: LibraryVisibility
libVisibility = LibraryVisibility
LibraryVisibilityPublic,
          libBuildInfo :: BuildInfo
libBuildInfo = BuildInfo
forall a. Monoid a => a
mempty {targetBuildDepends :: [Dependency]
targetBuildDepends = [Dependency]
cabalDeps}
        },
        condTreeConstraints :: [Dependency]
condTreeConstraints = [Dependency]
cabalDeps
      }
    cabalId :: PackageId
cabalId = PackageId -> PackageId
PackageId.toCabal PackageId {Version
PackageName
name :: PackageName
version :: Version
$sel:name:PackageId :: PackageName
$sel:version:PackageId :: Version
..}
    cabalDeps :: [Dependency]
cabalDeps = Dep -> Dependency
Dep.toCabal (Dep -> Dependency) -> [Dep] -> [Dependency]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Dep]
deps

mockSourcePackageDb :: SourcePackages -> SourcePackageDb
mockSourcePackageDb :: SourcePackages -> SourcePackageDb
mockSourcePackageDb SourcePackages
packages =
  SourcePackageDb {
    packageIndex :: PackageIndex UnresolvedSourcePackage
packageIndex = [UnresolvedSourcePackage] -> PackageIndex UnresolvedSourcePackage
forall pkg. Package pkg => [pkg] -> PackageIndex pkg
PackageIndex.fromList (SourcePackages
-> (PackageName -> Version -> [Dep] -> UnresolvedSourcePackage)
-> [UnresolvedSourcePackage]
forall map1 map2 k1 k2 v s1 s2 a.
(NMap map1 k1 map2 s1, NMap map2 k2 v s2) =>
map1 -> (k1 -> k2 -> v -> a) -> [a]
nTo1 SourcePackages
packages PackageName -> Version -> [Dep] -> UnresolvedSourcePackage
mockSourcePackage),
    packagePreferences :: Map PackageName VersionRange
packagePreferences = []
  }

managedSourcePackageVersions :: Packages ManagedPackage -> SourcePackageVersions
managedSourcePackageVersions :: Packages ManagedPackage -> SourcePackageVersions
managedSourcePackageVersions =
  (LocalPackage -> ManagedPackage -> (PackageName, [Version]))
-> Packages ManagedPackage -> SourcePackageVersions
forall map1 k1 v1 sort1 map2 k2 v2 sort2.
(NMap map1 k1 v1 sort1, NMap map2 k2 v2 sort2) =>
(k1 -> v1 -> (k2, v2)) -> map1 -> map2
nTransform \ (LocalPackage PackageName
name) ManagedPackage
package -> (PackageName
name, [ManagedPackage
package.version])

managedSourcePackage :: ManagedPackage -> UnresolvedSourcePackage
managedSourcePackage :: ManagedPackage -> UnresolvedSourcePackage
managedSourcePackage ManagedPackage
package =
  PackageName -> Version -> [Dep] -> UnresolvedSourcePackage
mockSourcePackage (LocalPackage -> PackageName
localPackageName ManagedPackage
package.package) ManagedPackage
package.version (ManagedPackage -> [Dep]
ManagedPackage.deps ManagedPackage
package)

managedPackageIndex :: Packages ManagedPackage -> PackageIndex UnresolvedSourcePackage
managedPackageIndex :: Packages ManagedPackage -> PackageIndex UnresolvedSourcePackage
managedPackageIndex Packages ManagedPackage
packages =
  [UnresolvedSourcePackage] -> PackageIndex UnresolvedSourcePackage
forall pkg. Package pkg => [pkg] -> PackageIndex pkg
PackageIndex.fromList (ManagedPackage -> UnresolvedSourcePackage
managedSourcePackage (ManagedPackage -> UnresolvedSourcePackage)
-> [ManagedPackage] -> [UnresolvedSourcePackage]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Map LocalPackage ManagedPackage -> [ManagedPackage]
forall k a. Map k a -> [a]
Map.elems (Packages ManagedPackage -> Map LocalPackage ManagedPackage
forall map k v sort. NMap map k v sort => map -> Map k v
nGet Packages ManagedPackage
packages))

dbWithManaged :: Packages ManagedPackage -> SourcePackageDb -> SourcePackageDb
dbWithManaged :: Packages ManagedPackage -> SourcePackageDb -> SourcePackageDb
dbWithManaged Packages ManagedPackage
packages SourcePackageDb {PackageIndex UnresolvedSourcePackage
packageIndex :: SourcePackageDb -> PackageIndex UnresolvedSourcePackage
packageIndex :: PackageIndex UnresolvedSourcePackage
packageIndex, Map PackageName VersionRange
packagePreferences :: SourcePackageDb -> Map PackageName VersionRange
packagePreferences :: Map PackageName VersionRange
packagePreferences} =
  SourcePackageDb {
    packageIndex :: PackageIndex UnresolvedSourcePackage
packageIndex = PackageIndex UnresolvedSourcePackage
-> PackageIndex UnresolvedSourcePackage
-> PackageIndex UnresolvedSourcePackage
forall pkg.
Package pkg =>
PackageIndex pkg -> PackageIndex pkg -> PackageIndex pkg
PackageIndex.merge PackageIndex UnresolvedSourcePackage
packageIndex (Packages ManagedPackage -> PackageIndex UnresolvedSourcePackage
managedPackageIndex Packages ManagedPackage
packages),
    Map PackageName VersionRange
packagePreferences :: Map PackageName VersionRange
packagePreferences :: Map PackageName VersionRange
packagePreferences
  }