Distribution/Types/UnitId.hs

    {-# LANGUAGE DeriveDataTypeable #-}
    {-# LANGUAGE DeriveGeneric #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    {-# LANGUAGE FlexibleContexts #-}

    module Distribution.Types.UnitId
      ( UnitId, unUnitId, mkUnitId
      , DefUnitId
      , unsafeMkDefUnitId
      , unDefUnitId
      , newSimpleUnitId
      , mkLegacyUnitId
      , getHSLibraryName
      ) where

    import Prelude ()
    import Distribution.Compat.Prelude
    import Distribution.Utils.ShortText

    import qualified Distribution.Compat.CharParsing as P
    import Distribution.Pretty
    import Distribution.Parsec
    import Distribution.Types.ComponentId
    import Distribution.Types.PackageId

    import Text.PrettyPrint (text)

    -- | A unit identifier identifies a (possibly instantiated)
    -- package/component that can be installed the installed package
    -- database.  There are several types of components that can be
    -- installed:
    --
    --  * A traditional library with no holes, so that 'unitIdHash'
    --    is @Nothing@.  In the absence of Backpack, 'UnitId'
    --    is the same as a 'ComponentId'.
    --
    --  * An indefinite, Backpack library with holes.  In this case,
    --    'unitIdHash' is still @Nothing@, but in the install,
    --    there are only interfaces, no compiled objects.
    --
    --  * An instantiated Backpack library with all the holes
    --    filled in.  'unitIdHash' is a @Just@ a hash of the
    --    instantiating mapping.
    --
    -- A unit is a component plus the additional information on how the
    -- holes are filled in. Thus there is a one to many relationship: for a
    -- particular component there are many different ways of filling in the
    -- holes, and each different combination is a unit (and has a separate
    -- 'UnitId').
    --
    -- 'UnitId' is distinct from 'OpenUnitId', in that it is always
    -- installed, whereas 'OpenUnitId' are intermediate unit identities
    -- that arise during mixin linking, and don't necessarily correspond
    -- to any actually installed unit.  Since the mapping is not actually
    -- recorded in a 'UnitId', you can't actually substitute over them
    -- (but you can substitute over 'OpenUnitId').  See also
    -- "Distribution.Backpack.FullUnitId" for a mechanism for expanding an
    -- instantiated 'UnitId' to retrieve its mapping.
    --
    -- Backwards compatibility note: if you need to get the string
    -- representation of a UnitId to pass, e.g., as a @-package-id@
    -- flag, use the 'display' function, which will work on all
    -- versions of Cabal.
    --
    newtype UnitId = UnitId ShortText
      deriving (Generic, Read, Show, Eq, Ord, Typeable, Data, NFData)

    instance Binary UnitId
    instance Structured UnitId

    -- | The textual format for 'UnitId' coincides with the format
    -- GHC accepts for @-package-id@.
    --
    instance Pretty UnitId where
        pretty = text . unUnitId

    -- | The textual format for 'UnitId' coincides with the format
    -- GHC accepts for @-package-id@.
    --
    instance Parsec UnitId where
        parsec = mkUnitId <$> P.munch1 (\c -> isAlphaNum c || c `elem` "-_.+")

    -- | If you need backwards compatibility, consider using 'display'
    -- instead, which is supported by all versions of Cabal.
    --
    unUnitId :: UnitId -> String
    unUnitId (UnitId s) = fromShortText s

    mkUnitId :: String -> UnitId
    mkUnitId = UnitId . toShortText

    -- | 'mkUnitId'
    --
    -- @since 2.0.0.2
    instance IsString UnitId where
        fromString = mkUnitId

    -- | Create a unit identity with no associated hash directly
    -- from a 'ComponentId'.
    newSimpleUnitId :: ComponentId -> UnitId
    newSimpleUnitId = mkUnitId . unComponentId

    -- | Make an old-style UnitId from a package identifier.
    -- Assumed to be for the public library
    mkLegacyUnitId :: PackageId -> UnitId
    mkLegacyUnitId = newSimpleUnitId . mkComponentId . prettyShow

    -- | Returns library name prefixed with HS, suitable for filenames
    getHSLibraryName :: UnitId -> String
    getHSLibraryName uid = "HS" ++ prettyShow uid

    -- | A 'UnitId' for a definite package.  The 'DefUnitId' invariant says
    -- that a 'UnitId' identified this way is definite; i.e., it has no
    -- unfilled holes.
    newtype DefUnitId = DefUnitId { unDefUnitId :: UnitId }
      deriving (Generic, Read, Show, Eq, Ord, Typeable, Data, Binary, NFData, Pretty)

    instance Structured DefUnitId

    -- Workaround for a GHC 8.0.1 bug, see
    -- https://github.com/haskell/cabal/issues/4793#issuecomment-334258288
    instance Parsec DefUnitId where
      parsec = DefUnitId <$> parsec

    -- | Unsafely create a 'DefUnitId' from a 'UnitId'.  Your responsibility
    -- is to ensure that the 'DefUnitId' invariant holds.
    unsafeMkDefUnitId :: UnitId -> DefUnitId
    unsafeMkDefUnitId = DefUnitId