@@ -7,6 +7,9 @@ module Distribution.Types.UnitId
77 ( UnitId
88 , unUnitId
99 , mkUnitId
10+ , isPartialUnitId
11+ , addPrefixToUnitId
12+ , addSuffixToUnitId
1013 , DefUnitId
1114 , unsafeMkDefUnitId
1215 , unDefUnitId
@@ -27,6 +30,11 @@ import Distribution.Types.PackageId
2730
2831import Text.PrettyPrint (text )
2932
33+ import GHC.Stack (HasCallStack )
34+ import Data.List (isInfixOf )
35+
36+ import Unsafe.Coerce (unsafeCoerce )
37+
3038-- | A unit identifier identifies a (possibly instantiated)
3139-- package/component that can be installed the installed package
3240-- database. There are several types of components that can be
@@ -63,11 +71,24 @@ import Text.PrettyPrint (text)
6371-- representation of a UnitId to pass, e.g., as a @-package-id@
6472-- flag, use the 'display' function, which will work on all
6573-- versions of Cabal.
66- newtype UnitId = UnitId ShortText
67- deriving (Generic , Read , Show , Eq , Ord , Data , NFData )
74+ data UnitId = UnitId ShortText ShortText Bool
75+ | PartialUnitId ShortText
76+ deriving (Generic , Read , Show , Data )
77+
78+ instance Eq UnitId where
79+ (UnitId c1 s1 _) == (UnitId c2 s2 _) = c1 == c2 && s1 == s2
80+ (PartialUnitId s1) == (PartialUnitId s2) = s1 == s2
81+ _ == _ = False
82+
83+ instance Ord UnitId where
84+ compare (UnitId c1 s1 _) (UnitId c2 s2 _) = compare (c1, s1) (c2, s2)
85+ compare (PartialUnitId s1) (PartialUnitId s2) = compare s1 s2
86+ compare (PartialUnitId _) _ = LT
87+ compare _ (PartialUnitId _) = GT
6888
6989instance Binary UnitId
7090instance Structured UnitId
91+ instance NFData UnitId
7192
7293-- | The textual format for 'UnitId' coincides with the format
7394-- GHC accepts for @-package-id@.
@@ -77,22 +98,54 @@ instance Pretty UnitId where
7798-- | The textual format for 'UnitId' coincides with the format
7899-- GHC accepts for @-package-id@.
79100instance Parsec UnitId where
80- parsec = mkUnitId <$> P. munch1 isUnitChar
101+ parsec = P. try (mkUnitId' <$> compid <* P. char ' _' <*> P. munch1 isUnitChar <*> return False )
102+ <|> (mkPartialUnitId <$> P. munch1 isUnitChar)
81103 where
104+ compid = (\ f v -> f ++ " -" ++ v) <$> P. munch1 isAlpha <* P. char ' -' <*> P. munch1 isVerChar
105+ isVerChar :: Char -> Bool
106+ isVerChar c = c `elem` ' .' : [' 0' .. ' 9' ]
82107 -- https://gitlab.haskell.org/ghc/ghc/issues/17752
83108 isUnitChar ' -' = True
84109 isUnitChar ' _' = True
85110 isUnitChar ' .' = True
86111 isUnitChar ' +' = True
87112 isUnitChar c = isAlphaNum c
88113
114+ isPartialUnitId :: HasCallStack => UnitId -> Bool
115+ isPartialUnitId (PartialUnitId _) = True
116+ isPartialUnitId _ = False
117+
118+ addPrefixToUnitId :: HasCallStack => String -> UnitId -> UnitId
119+ addPrefixToUnitId prefix (PartialUnitId s) = UnitId (toShortText prefix) s True
120+ addPrefixToUnitId prefix uid@ (UnitId _ _ _) = error $ " addPrefixToUnitId: UnitId " ++ show uid ++ " already has a prefix; can't add: " ++ prefix
121+
122+ addSuffixToUnitId :: HasCallStack => String -> UnitId -> UnitId
123+ addSuffixToUnitId suffix (UnitId c s fromPartial) = UnitId c (s <> toShortText suffix) fromPartial
124+ addSuffixToUnitId suffix (PartialUnitId s) = PartialUnitId (s <> toShortText suffix)
125+
126+
127+ dropPrefixFromUnitId :: HasCallStack => UnitId -> UnitId
128+ dropPrefixFromUnitId (PartialUnitId s) = PartialUnitId s
129+ dropPrefixFromUnitId (UnitId _c s _fromPartial) = PartialUnitId s
130+
89131-- | If you need backwards compatibility, consider using 'display'
90132-- instead, which is supported by all versions of Cabal.
91- unUnitId :: UnitId -> String
92- unUnitId (UnitId s) = fromShortText s
133+ unUnitId :: HasCallStack => UnitId -> String
134+ unUnitId (UnitId c s False ) = fromShortText c ++ ' _' : fromShortText s
135+ unUnitId (UnitId c s True ) = fromShortText s
136+ unUnitId (PartialUnitId s) = fromShortText s
137+
138+ mkUnitId :: HasCallStack => String -> UnitId
139+ mkUnitId s = case (simpleParsec s) of
140+ Just uid@ UnitId {} -> uid
141+ Just uid@ PartialUnitId {} -> uid -- error $ "mkUnitId: `" ++ s ++ "' is a partial unit id, not a full one."
142+ _ -> error $ " Unable to parse UnitId: `" ++ s ++ " '."
143+
144+ mkUnitId' :: HasCallStack => String -> String -> Bool -> UnitId
145+ mkUnitId' c i b = UnitId (toShortText c) (toShortText i) b
93146
94- mkUnitId :: String -> UnitId
95- mkUnitId = UnitId . toShortText
147+ mkPartialUnitId :: HasCallStack => String -> UnitId
148+ mkPartialUnitId s = PartialUnitId ( toShortText s)
96149
97150-- | 'mkUnitId'
98151--
@@ -102,17 +155,17 @@ instance IsString UnitId where
102155
103156-- | Create a unit identity with no associated hash directly
104157-- from a 'ComponentId'.
105- newSimpleUnitId :: ComponentId -> UnitId
106- newSimpleUnitId = mkUnitId . unComponentId
158+ newSimpleUnitId :: HasCallStack => ComponentId -> UnitId
159+ newSimpleUnitId = unsafeCoerce
107160
108161-- | Make an old-style UnitId from a package identifier.
109162-- Assumed to be for the public library
110- mkLegacyUnitId :: PackageId -> UnitId
163+ mkLegacyUnitId :: HasCallStack => PackageId -> UnitId
111164mkLegacyUnitId = newSimpleUnitId . mkComponentId . prettyShow
112165
113166-- | Returns library name prefixed with HS, suitable for filenames
114167getHSLibraryName :: UnitId -> String
115- getHSLibraryName uid = " HS" ++ prettyShow uid
168+ getHSLibraryName uid = " HS" ++ prettyShow (dropPrefixFromUnitId uid)
116169
117170-- | A 'UnitId' for a definite package. The 'DefUnitId' invariant says
118171-- that a 'UnitId' identified this way is definite; i.e., it has no
0 commit comments