cabal-install-1.24.0.0: Distribution/Client/Dependency/Modular/Package.hs
{-# LANGUAGE DeriveFunctor #-}
module Distribution.Client.Dependency.Modular.Package
( I(..)
, Loc(..)
, PackageId
, PackageIdentifier(..)
, PackageName(..)
, PI(..)
, PN
, PP(..)
, Namespace(..)
, Qualifier(..)
, QPN
, QPV
, Q(..)
, instI
, makeIndependent
, primaryPP
, showI
, showPI
, showQPN
, unPN
) where
import Data.List as L
import Distribution.Package -- from Cabal
import Distribution.Text -- from Cabal
import Distribution.Client.Dependency.Modular.Version
-- | A package name.
type PN = PackageName
-- | Unpacking a package name.
unPN :: PN -> String
unPN (PackageName pn) = pn
-- | Package version. A package name plus a version number.
type PV = PackageId
-- | Qualified package version.
type QPV = Q PV
-- | Package id. Currently just a black-box string.
type PId = UnitId
-- | Location. Info about whether a package is installed or not, and where
-- exactly it is located. For installed packages, uniquely identifies the
-- package instance via its 'PId'.
--
-- TODO: More information is needed about the repo.
data Loc = Inst PId | InRepo
deriving (Eq, Ord, Show)
-- | Instance. A version number and a location.
data I = I Ver Loc
deriving (Eq, Ord, Show)
-- | String representation of an instance.
showI :: I -> String
showI (I v InRepo) = showVer v
showI (I v (Inst uid)) = showVer v ++ "/installed" ++ shortId uid
where
-- A hack to extract the beginning of the package ABI hash
shortId (SimpleUnitId (ComponentId i))
= snip (splitAt 4) (++ "...")
. snip ((\ (x, y) -> (reverse x, y)) . break (=='-') . reverse) ('-':)
$ i
snip p f xs = case p xs of
(ys, zs) -> (if L.null zs then id else f) ys
-- | Package instance. A package name and an instance.
data PI qpn = PI qpn I
deriving (Eq, Ord, Show, Functor)
-- | String representation of a package instance.
showPI :: PI QPN -> String
showPI (PI qpn i) = showQPN qpn ++ "-" ++ showI i
instI :: I -> Bool
instI (I _ (Inst _)) = True
instI _ = False
-- | A package path consists of a namespace and a package path inside that
-- namespace.
data PP = PP Namespace Qualifier
deriving (Eq, Ord, Show)
-- | Top-level namespace
--
-- Package choices in different namespaces are considered completely independent
-- by the solver.
data Namespace =
-- | The default namespace
DefaultNamespace
-- | Independent namespace
--
-- For now we just number these (rather than giving them more structure).
| Independent Int
deriving (Eq, Ord, Show)
-- | Qualifier of a package within a namespace (see 'PP')
data Qualifier =
-- | Top-level dependency in this namespace
Unqualified
-- | Any dependency on base is considered independent
--
-- This makes it possible to have base shims.
| Base PN
-- | Setup dependency
--
-- By rights setup dependencies ought to be nestable; after all, the setup
-- dependencies of a package might themselves have setup dependencies, which
-- are independent from everything else. However, this very quickly leads to
-- infinite search trees in the solver. Therefore we limit ourselves to
-- a single qualifier (within a given namespace).
| Setup PN
deriving (Eq, Ord, Show)
-- | Is the package in the primary group of packages. In particular this
-- does not include packages pulled in as setup deps.
--
primaryPP :: PP -> Bool
primaryPP (PP _ns q) = go q
where
go Unqualified = True
go (Base _) = True
go (Setup _) = False
-- | String representation of a package path.
--
-- NOTE: The result of 'showPP' is either empty or results in a period, so that
-- it can be prepended to a package name.
showPP :: PP -> String
showPP (PP ns q) =
case ns of
DefaultNamespace -> go q
Independent i -> show i ++ "." ++ go q
where
-- Print the qualifier
--
-- NOTE: the base qualifier is for a dependency _on_ base; the qualifier is
-- there to make sure different dependencies on base are all independent.
-- So we want to print something like @"A.base"@, where the @"A."@ part
-- is the qualifier and @"base"@ is the actual dependency (which, for the
-- 'Base' qualifier, will always be @base@).
go Unqualified = ""
go (Setup pn) = display pn ++ "-setup."
go (Base pn) = display pn ++ "."
-- | A qualified entity. Pairs a package path with the entity.
data Q a = Q PP a
deriving (Eq, Ord, Show)
-- | Standard string representation of a qualified entity.
showQ :: (a -> String) -> (Q a -> String)
showQ showa (Q pp x) = showPP pp ++ showa x
-- | Qualified package name.
type QPN = Q PN
-- | String representation of a qualified package path.
showQPN :: QPN -> String
showQPN = showQ display
-- | Create artificial parents for each of the package names, making
-- them all independent.
makeIndependent :: [PN] -> [QPN]
makeIndependent ps = [ Q pp pn | (pn, i) <- zip ps [0::Int ..]
, let pp = PP (Independent i) Unqualified
]