diff --git a/cabal-install/Distribution/Client/Targets.hs b/cabal-install/Distribution/Client/Targets.hs index b169acd5a29bff574e138bc59c698df4cae89eea..fad2e042ebe3ae6dde7cfca16bd19f2a57de696f 100644 --- a/cabal-install/Distribution/Client/Targets.hs +++ b/cabal-install/Distribution/Client/Targets.hs @@ -67,6 +67,7 @@ import Distribution.Solver.Types.OptionalStanza import Distribution.Solver.Types.PackageConstraint import Distribution.Solver.Types.PackageIndex (PackageIndex) import qualified Distribution.Solver.Types.PackageIndex as PackageIndex +import Distribution.Solver.Types.PackagePath import Distribution.Solver.Types.SourcePackage import qualified Distribution.Client.World as World @@ -203,8 +204,9 @@ pkgSpecifierConstraints (NamedPackage _ constraints) = map toLpc constraints pkgSpecifierConstraints (SpecificSourcePackage pkg) = [LabeledPackageConstraint pc ConstraintSourceUserTarget] where - pc = PackageConstraintVersion (packageName pkg) - (thisVersion (packageVersion pkg)) + pc = PackageConstraint (Q (PackagePath DefaultNamespace Unqualified) + (packageName pkg)) $ + PackagePropertyVersion (thisVersion (packageVersion pkg)) -- ------------------------------------------------------------ -- * Parsing and checking user targets @@ -414,6 +416,12 @@ data PackageTarget pkg = -- * Converting user targets to package targets -- ------------------------------------------------------------ +dependencyToConstraints :: Dependency -> [PackageConstraint] +dependencyToConstraints (Dependency name vrange) = + [ PackageConstraint (Q defaultPackagePath name) $ + PackagePropertyVersion vrange + | not (isAnyVersion vrange) ] + -- | Given a user-specified target, expand it to a bunch of package targets -- (each of which refers to only one package). -- @@ -422,19 +430,17 @@ expandUserTarget :: FilePath -> IO [PackageTarget (PackageLocation ())] expandUserTarget worldFile userTarget = case userTarget of - UserTargetNamed (Dependency name vrange) -> - let constraints = [ PackageConstraintVersion name vrange - | not (isAnyVersion vrange) ] - in return [PackageTargetNamedFuzzy name constraints userTarget] + UserTargetNamed dep@(Dependency name _) -> + return [PackageTargetNamedFuzzy name (dependencyToConstraints dep) userTarget] UserTargetWorld -> do worldPkgs <- World.getContents worldFile --TODO: should we warn if there are no world targets? return [ PackageTargetNamed name constraints userTarget - | World.WorldPkgInfo (Dependency name vrange) flags <- worldPkgs - , let constraints = [ PackageConstraintVersion name vrange - | not (isAnyVersion vrange) ] - ++ [ PackageConstraintFlags name flags + | World.WorldPkgInfo dep@(Dependency name _) flags <- worldPkgs + , let constraints = dependencyToConstraints dep + ++ [ PackageConstraint (Q defaultPackagePath name) $ + PackagePropertyFlags flags | not (null flags) ] ] UserTargetLocalDir dir -> @@ -701,40 +707,75 @@ extraPackageNameEnv names = PackageNameEnv pkgNameLookup -- * Package constraints -- ------------------------------------------------------------ -data UserConstraint = - UserConstraintVersion PackageName VersionRange - | UserConstraintInstalled PackageName - | UserConstraintSource PackageName - | UserConstraintFlags PackageName FlagAssignment - | UserConstraintStanzas PackageName [OptionalStanza] - deriving (Eq, Show, Generic) +-- | Restricted version of 'Qualifier' that a user may specify on the command line. +data UserQualifier = + -- | Top-level dependency. + UserUnqualified + + -- | Setup dependency. + | UserSetup PackageName + + -- | Executable dependency. + | UserExe PackageName PackageName + +fromUserQualifier :: UserQualifier -> Qualifier +fromUserQualifier UserUnqualified = Unqualified +fromUserQualifier (UserSetup name) = Setup name +fromUserQualifier (UserExe name1 name2) = Exe name1 name2 + +-- | A version of 'PackageProperty' that a user may specify on the command +-- line (currently, it has identical representation to 'PackageProperty'). +newtype UserProperty = UserProperty PackageProperty + +-- | Per-package constraints. Package constraints must be respected by the +-- solver. Multiple constraints for each package can be given, though obviously +-- it is possible to construct conflicting constraints (eg impossible version +-- range or inconsistent flag assignment). +-- +instance Text UserProperty where + disp (PackagePropertyVersion verrange) = disp verrange + disp PackagePropertyInstalled = Disp.text "installed" + disp PackagePropertySource = Disp.text "source" + disp (PackagePropertyFlags flags) = dispFlagAssignment flags + disp (PackagePropertyStanzas stanzas) = dispStanzas stanzas + where + dispStanzas = Disp.hsep . map dispStanza + dispStanza TestStanzas = Disp.text "test" + dispStanza BenchStanzas = Disp.text "bench" + + parse = + ((parse >>= return . PackagePropertyVersion) + +++ (do skipSpaces1 + _ <- Parse.string "installed" + return (PackagePropertyInstalled)) + +++ (do skipSpaces1 + _ <- Parse.string "source" + return (PackagePropertySource)) + +++ (do skipSpaces1 + _ <- Parse.string "test" + return (PackagePropertyStanzas [TestStanzas])) + +++ (do skipSpaces1 + _ <- Parse.string "bench" + return (PackagePropertyStanzas [BenchStanzas]))) + <++ (do skipSpaces1 + flags <- parseFlagAssignment + return (PackagePropertyFlags flags)) -instance Binary UserConstraint +-- | A restricted version of PackageConstraint that the user can specify on the +-- command line. +newtype UserConstraint = UserConstraint UserQualifier PackageName PackageProperty + deriving (Eq, Show) userConstraintPackageName :: UserConstraint -> PackageName -userConstraintPackageName uc = case uc of - UserConstraintVersion name _ -> name - UserConstraintInstalled name -> name - UserConstraintSource name -> name - UserConstraintFlags name _ -> name - UserConstraintStanzas name _ -> name +userConstraintPackageName (UserConstraint _ name _ = name userToPackageConstraint :: UserConstraint -> PackageConstraint --- At the moment, the types happen to be directly equivalent -userToPackageConstraint uc = case uc of - UserConstraintVersion name ver -> PackageConstraintVersion name ver - UserConstraintInstalled name -> PackageConstraintInstalled name - UserConstraintSource name -> PackageConstraintSource name - UserConstraintFlags name flags -> PackageConstraintFlags name flags - UserConstraintStanzas name stanzas -> PackageConstraintStanzas name stanzas +userToPackageConstraint (UserConstraint qual name pp) = + PackageConstraint (Q (fromUserQualifier qual) name) pp renamePackageConstraint :: PackageName -> PackageConstraint -> PackageConstraint -renamePackageConstraint name pc = case pc of - PackageConstraintVersion _ ver -> PackageConstraintVersion name ver - PackageConstraintInstalled _ -> PackageConstraintInstalled name - PackageConstraintSource _ -> PackageConstraintSource name - PackageConstraintFlags _ flags -> PackageConstraintFlags name flags - PackageConstraintStanzas _ stanzas -> PackageConstraintStanzas name stanzas +renamePackageConstraint name (PackageConstraint (Q path _) pp) = + PackageConstraint (Q path name) pp readUserConstraint :: String -> Either String UserConstraint readUserConstraint str = diff --git a/cabal-install/Distribution/Solver/Types/PackageConstraint.hs b/cabal-install/Distribution/Solver/Types/PackageConstraint.hs index 5b0f29d8a9196fda2fca767859ec25ae309199a4..5cea491d769382aafd88d50a597ab61c566dcfec 100644 --- a/cabal-install/Distribution/Solver/Types/PackageConstraint.hs +++ b/cabal-install/Distribution/Solver/Types/PackageConstraint.hs @@ -1,35 +1,54 @@ {-# LANGUAGE DeriveGeneric #-} module Distribution.Solver.Types.PackageConstraint ( + PackageProperty(..), PackageConstraint(..), - showPackageConstraint, +-- showPackageConstraint, ) where import Distribution.Compat.Binary (Binary(..)) import Distribution.PackageDescription (FlagAssignment, FlagName(..)) import Distribution.Package (PackageName) import Distribution.Solver.Types.OptionalStanza -import Distribution.Text (display) +import Distribution.Solver.Types.PackagePath (Qualified) +import Distribution.Text (Text(..), display) import Distribution.Version (VersionRange, simplifyVersionRange) import GHC.Generics (Generic) --- | Per-package constraints. Package constraints must be respected by the --- solver. Multiple constraints for each package can be given, though obviously --- it is possible to construct conflicting constraints (eg impossible version --- range or inconsistent flag assignment). --- + +data PackageProperty + = PackagePropertyVersion VersionRange + | PackagePropertyInstalled + | PackagePropertySource + | PackagePropertyFlags FlagAssignment + | PackagePropertyStanzas [OptionalStanza] + deriving (Eq, Show, Generic) + +instance Binary PackageProperty + data PackageConstraint - = PackageConstraintVersion PackageName VersionRange - | PackageConstraintInstalled PackageName - | PackageConstraintSource PackageName - | PackageConstraintFlags PackageName FlagAssignment - | PackageConstraintStanzas PackageName [OptionalStanza] + = PackageConstraint (Qualified PackageName) PackageProperty deriving (Eq, Show, Generic) instance Binary PackageConstraint +dispPackageProperty :: PackageProperty -> Disp.Doc + disp (PackagePropertyVersion verrange) = disp verrange + disp PackagePropertyInstalled = Disp.text "installed" + disp PackagePropertySource = Disp.text "source" + disp (PackagePropertyFlags flags) = dispFlagAssignment flags + disp (PackagePropertyStanzas stanzas) = dispStanzas stanzas + where + dispStanzas = Disp.hsep . map dispStanza + dispStanza TestStanzas = Disp.text "test" + dispStanza BenchStanzas = Disp.text "bench" + +dispPackageConstraint :: PackageConstraint -> Disp.Doc +dispPackageConstraint (PackageConstraint (Q path name) pp) = + + -- | Provide a textual representation of a package constraint -- for debugging purposes. --- + showPackageConstraint :: PackageConstraint -> String showPackageConstraint (PackageConstraintVersion pn vr) = display pn ++ " " ++ display (simplifyVersionRange vr) diff --git a/cabal-install/Distribution/Solver/Types/PackagePath.hs b/cabal-install/Distribution/Solver/Types/PackagePath.hs index 5ba2ecac4e53e85376853a81228ff26261fd7404..9c11bc3a1dd41d0f5355ff7d5646c24f6d549df7 100644 --- a/cabal-install/Distribution/Solver/Types/PackagePath.hs +++ b/cabal-install/Distribution/Solver/Types/PackagePath.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} module Distribution.Solver.Types.PackagePath ( PackagePath(..) , Namespace(..) @@ -5,15 +6,20 @@ module Distribution.Solver.Types.PackagePath , QPN , Qualified(..) , showQPN + , defaultPackagePath ) where +import Distribution.Compat.Binary (Binary(..)) import Distribution.Package -import Distribution.Text +import GHC.Generics (Generic) +import qualified Text.PrettyPrint as Disp -- | A package path consists of a namespace and a package path inside that -- namespace. data PackagePath = PackagePath Namespace Qualifier - deriving (Eq, Ord, Show) + deriving (Eq, Ord, Show, Generic) + +instance Binary PackagePath -- | Top-level namespace -- @@ -27,7 +33,9 @@ data Namespace = -- -- For now we just number these (rather than giving them more structure). | Independent Int - deriving (Eq, Ord, Show) + deriving (Eq, Ord, Show, Generic) + +instance Binary Namespace -- | Qualifier of a package within a namespace (see 'PackagePath') data Qualifier = @@ -59,17 +67,15 @@ data Qualifier = -- tracked only @pn2@, that would require us to pick only one -- version of an executable over the entire install plan.) | Exe PackageName PackageName - deriving (Eq, Ord, Show) + deriving (Eq, Generic, Ord, Show) --- | 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 :: PackagePath -> String -showPP (PackagePath ns q) = +instance Binary Qualifier + +dispPP :: PackagePath -> Disp.Doc +dispPP (PackagePath ns q) = case ns of DefaultNamespace -> go q - Independent i -> show i ++ "." ++ go q + Independent i -> Disp.int i <> Disp.char '.' <> go q where -- Print the qualifier -- @@ -78,14 +84,23 @@ showPP (PackagePath ns q) = -- 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 (Exe pn pn2) = display pn ++ "-" ++ display pn2 ++ "-exe." - go (Base pn) = display pn ++ "." + go Unqualified = empty + go (Setup pn) = disp pn <> Disp.text ":setup." + go (Exe pn pn2) = disp pn <> Disp.char ':' <> disp pn2 <> Disp.text ":exe." + go (Base pn) = display pn <> Disp.char '.' + +-- | 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 :: PackagePath -> String +showPP = display . dispPP -- | A qualified entity. Pairs a package path with the entity. data Qualified a = Q PackagePath a - deriving (Eq, Ord, Show) + deriving (Eq, Ord, Show, Generic) + +instance Binary a => Binary (Qualified a) -- | Standard string representation of a qualified entity. showQ :: (a -> String) -> (Qualified a -> String) @@ -97,3 +112,6 @@ type QPN = Qualified PackageName -- | String representation of a qualified package path. showQPN :: QPN -> String showQPN = showQ display + +defaultPackagePath :: PackagePath +defaultPackagePath = PackagePath DefaultNamespace Unqualified