packages feed

cabal-install-solver 3.10.3.0 → 3.12.1.0

raw patch · 15 files changed

+385/−188 lines, 15 filesdep +directorydep +network-uridep ~Cabaldep ~Cabal-syntaxdep ~basenew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: directory, network-uri

Dependency ranges changed: Cabal, Cabal-syntax, base, tasty-quickcheck

API changes (from Hackage documentation)

- Distribution.Solver.Modular: [allowBootLibInstalls] :: SolverConfig -> AllowBootLibInstalls
- Distribution.Solver.Modular.ConflictSet: instance GHC.Classes.Ord Distribution.Solver.Modular.ConflictSet.ConflictSet
- Distribution.Solver.Modular.Preference: requireInstalled :: (PN -> Bool) -> EndoTreeTrav d c
- Distribution.Solver.Modular.Solver: [allowBootLibInstalls] :: SolverConfig -> AllowBootLibInstalls
- Distribution.Solver.Modular.Tree: CannotInstall :: FailReason
- Distribution.Solver.Types.ConstraintSource: ConstraintSourceNonUpgradeablePackage :: ConstraintSource
+ Distribution.Solver.Compat.Prelude: traceM :: Applicative f => String -> f ()
+ Distribution.Solver.Compat.Prelude: traceShowM :: (Show a, Applicative f) => a -> f ()
+ Distribution.Solver.Types.ComponentDeps: mapDeps :: (Component -> a -> b) -> ComponentDeps a -> ComponentDeps b
+ Distribution.Solver.Types.ConstraintSource: ConstraintSourceMultiRepl :: ConstraintSource
+ Distribution.Solver.Types.ConstraintSource: ConstraintSourceNonReinstallablePackage :: ConstraintSource
+ Distribution.Solver.Types.ProjectConfigPath: ProjectConfigPath :: NonEmpty FilePath -> ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: canonicalizeConfigPath :: FilePath -> ProjectConfigPath -> IO ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: consProjectConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: cyclicalImportMsg :: ProjectConfigPath -> Doc
+ Distribution.Solver.Types.ProjectConfigPath: docProjectConfigPath :: ProjectConfigPath -> Doc
+ Distribution.Solver.Types.ProjectConfigPath: docProjectConfigPathFailReason :: VR -> ProjectConfigPath -> Doc
+ Distribution.Solver.Types.ProjectConfigPath: docProjectConfigPaths :: [ProjectConfigPath] -> Doc
+ Distribution.Solver.Types.ProjectConfigPath: instance Data.Binary.Class.Binary Distribution.Solver.Types.ProjectConfigPath.ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: instance Distribution.Utils.Structured.Structured Distribution.Solver.Types.ProjectConfigPath.ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: instance GHC.Classes.Eq Distribution.Solver.Types.ProjectConfigPath.ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: instance GHC.Classes.Ord Distribution.Solver.Types.ProjectConfigPath.ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: instance GHC.Generics.Generic Distribution.Solver.Types.ProjectConfigPath.ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: instance GHC.Show.Show Distribution.Solver.Types.ProjectConfigPath.ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: isCyclicConfigPath :: ProjectConfigPath -> Bool
+ Distribution.Solver.Types.ProjectConfigPath: newtype ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: nullProjectConfigPath :: ProjectConfigPath
+ Distribution.Solver.Types.ProjectConfigPath: projectConfigPathRoot :: ProjectConfigPath -> FilePath
- Distribution.Solver.Modular: SolverConfig :: ReorderGoals -> CountConflicts -> FineGrainedConflicts -> MinimizeConflictSet -> IndependentGoals -> AvoidReinstalls -> ShadowPkgs -> StrongFlags -> AllowBootLibInstalls -> OnlyConstrained -> Maybe Int -> EnableBackjumping -> SolveExecutables -> Maybe (Variable QPN -> Variable QPN -> Ordering) -> Verbosity -> PruneAfterFirstSuccess -> SolverConfig
+ Distribution.Solver.Modular: SolverConfig :: ReorderGoals -> CountConflicts -> FineGrainedConflicts -> MinimizeConflictSet -> IndependentGoals -> AvoidReinstalls -> ShadowPkgs -> StrongFlags -> OnlyConstrained -> Maybe Int -> EnableBackjumping -> SolveExecutables -> Maybe (Variable QPN -> Variable QPN -> Ordering) -> Verbosity -> PruneAfterFirstSuccess -> SolverConfig
- Distribution.Solver.Modular.Solver: SolverConfig :: ReorderGoals -> CountConflicts -> FineGrainedConflicts -> MinimizeConflictSet -> IndependentGoals -> AvoidReinstalls -> ShadowPkgs -> StrongFlags -> AllowBootLibInstalls -> OnlyConstrained -> Maybe Int -> EnableBackjumping -> SolveExecutables -> Maybe (Variable QPN -> Variable QPN -> Ordering) -> Verbosity -> PruneAfterFirstSuccess -> SolverConfig
+ Distribution.Solver.Modular.Solver: SolverConfig :: ReorderGoals -> CountConflicts -> FineGrainedConflicts -> MinimizeConflictSet -> IndependentGoals -> AvoidReinstalls -> ShadowPkgs -> StrongFlags -> OnlyConstrained -> Maybe Int -> EnableBackjumping -> SolveExecutables -> Maybe (Variable QPN -> Variable QPN -> Ordering) -> Verbosity -> PruneAfterFirstSuccess -> SolverConfig
- Distribution.Solver.Types.ConstraintSource: ConstraintSourceProjectConfig :: FilePath -> ConstraintSource
+ Distribution.Solver.Types.ConstraintSource: ConstraintSourceProjectConfig :: ProjectConfigPath -> ConstraintSource

Files

ChangeLog.md view
@@ -1,1 +1,1 @@-Please see https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.10.3.0.md+Please see https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.12.1.0.md
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2003-2023, Cabal Development Team.+Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders.  See */LICENSE for the copyright holders of the subcomponents.
cabal-install-solver.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name:          cabal-install-solver-version:       3.10.3.0+version:       3.12.1.0 synopsis:      The command-line interface for Cabal and Hackage. description:   The solver component used in cabal-install command-line program@@ -11,7 +11,7 @@ license-file:  LICENSE author:        Cabal Development Team (see AUTHORS file) maintainer:    Cabal Development Team <cabal-devel@haskell.org>-copyright:     2003-2023, Cabal Development Team+copyright:     2003-2024, Cabal Development Team category:      Distribution build-type:    Simple extra-doc-files:@@ -27,11 +27,6 @@   default:     False   manual:      True -flag debug-conflict-sets-  description: Add additional information to ConflictSets-  default:     False-  manual:      True- flag debug-tracetree   description: Compile in support for tracetree (used to debug the solver)   default:     False@@ -47,6 +42,7 @@    if impl(ghc <8.8)     ghc-options: -Wnoncanonical-monadfail-instances+   if impl(ghc >=8.10)     ghc-options: -Wunused-packages @@ -96,6 +92,7 @@     Distribution.Solver.Types.PackagePreferences     Distribution.Solver.Types.PkgConfigDb     Distribution.Solver.Types.Progress+    Distribution.Solver.Types.ProjectConfigPath     Distribution.Solver.Types.ResolverPackage     Distribution.Solver.Types.Settings     Distribution.Solver.Types.SolverId@@ -105,14 +102,16 @@    build-depends:     , array         >=0.4      && <0.6-    , base          >=4.10     && <4.20+    , base          >=4.11     && <4.21     , bytestring    >=0.10.6.0 && <0.13-    , Cabal         ^>=3.10-    , Cabal-syntax  ^>=3.10+    , Cabal         ^>=3.12.1.0+    , Cabal-syntax  ^>=3.12.1.0     , containers    >=0.5.6.2  && <0.8     , edit-distance ^>= 0.2.2+    , directory     >= 1.3.7.0  && < 1.4     , filepath      ^>=1.4.0.0 || ^>=1.5.0.0     , mtl           >=2.0      && <2.4+    , network-uri   >= 2.6.0.2 && < 2.7     , pretty        ^>=1.1     , transformers  >=0.4.2.0  && <0.7     , text          (>= 1.2.3.0  && < 1.3) || (>= 2.0 && < 2.2)@@ -120,10 +119,6 @@   if flag(debug-expensive-assertions)     cpp-options: -DDEBUG_EXPENSIVE_ASSERTIONS -  if flag(debug-conflict-sets)-    cpp-options:   -DDEBUG_CONFLICT_SETS-    build-depends: base >=4.9-   if flag(debug-tracetree)     cpp-options:   -DDEBUG_TRACETREE     build-depends: tracetree ^>=0.1@@ -139,10 +134,10 @@      UnitTests.Distribution.Solver.Modular.MessageUtils     build-depends:-     , base        >= 4.10  && <4.20+     , base        >= 4.11  && <4.21      , Cabal      , Cabal-syntax      , cabal-install-solver      , tasty       >= 1.2.3 && <1.6-     , tasty-quickcheck+     , tasty-quickcheck <0.11      , tasty-hunit >= 0.10
src/Distribution/Solver/Modular.hs view
@@ -60,7 +60,7 @@ -- solver. Performs the necessary translations before and after. modularResolver :: SolverConfig -> DependencyResolver loc modularResolver sc (Platform arch os) cinfo iidx sidx pkgConfigDB pprefs pcs pns =-  fmap (uncurry postprocess) $ -- convert install plan+  uncurry postprocess <$> -- convert install plan   solve' sc cinfo idx pkgConfigDB pprefs gcs pns     where       -- Indices have to be converted into solver-specific uniform index.@@ -275,7 +275,7 @@                              ++ "conflict set: " ++ showCS cs') $                   ExhaustiveSearch smallestKnownCS smallestKnownCM             BackjumpLimitReached ->-                failWith ("Reached backjump limit while minimizing conflict set.")+                failWith "Reached backjump limit while minimizing conflict set."                          BackjumpLimitReached       where         varStr = "\"" ++ showVar v ++ "\""
src/Distribution/Solver/Modular/ConflictSet.hs view
@@ -1,7 +1,3 @@-{-# LANGUAGE CPP #-}-#ifdef DEBUG_CONFLICT_SETS-{-# LANGUAGE ImplicitParams #-}-#endif -- | Conflict sets -- -- Intended for double import@@ -13,9 +9,6 @@   , Conflict(..)   , ConflictMap   , OrderedVersionRange(..)-#ifdef DEBUG_CONFLICT_SETS-  , conflictSetOrigin-#endif   , showConflictSet   , showCSSortedByFrequency   , showCSWithFrequency@@ -44,36 +37,17 @@ import qualified Data.Map.Strict as M import qualified Data.Set as S -#ifdef DEBUG_CONFLICT_SETS-import Data.Tree-import GHC.Stack-#endif- import Distribution.Solver.Modular.Var import Distribution.Solver.Modular.Version import Distribution.Solver.Types.PackagePath  -- | The set of variables involved in a solver conflict, each paired with -- details about the conflict.-data ConflictSet = CS {+newtype ConflictSet = CS {     -- | The set of variables involved in the conflict-    conflictSetToMap :: !(Map (Var QPN) (Set Conflict))--#ifdef DEBUG_CONFLICT_SETS-    -- | The origin of the conflict set-    ---    -- When @DEBUG_CONFLICT_SETS@ is defined @(-f debug-conflict-sets)@,-    -- we record the origin of every conflict set. For new conflict sets-    -- ('empty', 'fromVars', ..) we just record the 'CallStack'; for operations-    -- that construct new conflict sets from existing conflict sets ('union',-    -- 'filter', ..)  we record the 'CallStack' to the call to the combinator-    -- as well as the 'CallStack's of the input conflict sets.-    ---    -- Requires @GHC >= 7.10@.-  , conflictSetOrigin :: Tree CallStack-#endif+    conflictSetToMap :: Map (Var QPN) (Set Conflict)   }-  deriving (Show)+  deriving (Eq, Show)  -- | More detailed information about how a conflict set variable caused a -- conflict. This information can be used to determine whether a second value@@ -112,12 +86,6 @@ instance Ord OrderedVersionRange where   compare = compare `on` show -instance Eq ConflictSet where-  (==) = (==) `on` conflictSetToMap--instance Ord ConflictSet where-  compare = compare `on` conflictSetToMap- showConflictSet :: ConflictSet -> String showConflictSet = intercalate ", " . map showVar . toList @@ -147,40 +115,19 @@ toList :: ConflictSet -> [Var QPN] toList = M.keys . conflictSetToMap -union ::-#ifdef DEBUG_CONFLICT_SETS-  (?loc :: CallStack) =>-#endif-  ConflictSet -> ConflictSet -> ConflictSet+union :: ConflictSet -> ConflictSet -> ConflictSet union cs cs' = CS {       conflictSetToMap = M.unionWith S.union (conflictSetToMap cs) (conflictSetToMap cs')-#ifdef DEBUG_CONFLICT_SETS-    , conflictSetOrigin = Node ?loc (map conflictSetOrigin [cs, cs'])-#endif     } -unions ::-#ifdef DEBUG_CONFLICT_SETS-  (?loc :: CallStack) =>-#endif-  [ConflictSet] -> ConflictSet+unions :: [ConflictSet] -> ConflictSet unions css = CS {       conflictSetToMap = M.unionsWith S.union (map conflictSetToMap css)-#ifdef DEBUG_CONFLICT_SETS-    , conflictSetOrigin = Node ?loc (map conflictSetOrigin css)-#endif     } -insert ::-#ifdef DEBUG_CONFLICT_SETS-  (?loc :: CallStack) =>-#endif-  Var QPN -> ConflictSet -> ConflictSet+insert :: Var QPN -> ConflictSet -> ConflictSet insert var cs = CS {       conflictSetToMap = M.insert var (S.singleton OtherConflict) (conflictSetToMap cs)-#ifdef DEBUG_CONFLICT_SETS-    , conflictSetOrigin = Node ?loc [conflictSetOrigin cs]-#endif     }  delete :: Var QPN -> ConflictSet -> ConflictSet@@ -188,35 +135,17 @@       conflictSetToMap = M.delete var (conflictSetToMap cs)     } -empty ::-#ifdef DEBUG_CONFLICT_SETS-  (?loc :: CallStack) =>-#endif-  ConflictSet+empty :: ConflictSet empty = CS {       conflictSetToMap = M.empty-#ifdef DEBUG_CONFLICT_SETS-    , conflictSetOrigin = Node ?loc []-#endif     } -singleton ::-#ifdef DEBUG_CONFLICT_SETS-  (?loc :: CallStack) =>-#endif-  Var QPN -> ConflictSet+singleton :: Var QPN -> ConflictSet singleton var = singletonWithConflict var OtherConflict -singletonWithConflict ::-#ifdef DEBUG_CONFLICT_SETS-  (?loc :: CallStack) =>-#endif-  Var QPN -> Conflict -> ConflictSet+singletonWithConflict :: Var QPN -> Conflict -> ConflictSet singletonWithConflict var conflict = CS {       conflictSetToMap = M.singleton var (S.singleton conflict)-#ifdef DEBUG_CONFLICT_SETS-    , conflictSetOrigin = Node ?loc []-#endif     }  size :: ConflictSet -> Int@@ -228,17 +157,9 @@ lookup :: Var QPN -> ConflictSet -> Maybe (Set Conflict) lookup var = M.lookup var . conflictSetToMap -fromList ::-#ifdef DEBUG_CONFLICT_SETS-  (?loc :: CallStack) =>-#endif-  [Var QPN] -> ConflictSet+fromList :: [Var QPN] -> ConflictSet fromList vars = CS {       conflictSetToMap = M.fromList [(var, S.singleton OtherConflict) | var <- vars]-#ifdef DEBUG_CONFLICT_SETS-    , conflictSetOrigin = Node ?loc []-#endif     }  type ConflictMap = Map (Var QPN) Int-
src/Distribution/Solver/Modular/Linking.hs view
@@ -85,11 +85,11 @@     go :: Tree d c -> Validate (Tree d c)      go (PChoice qpn rdm gr       cs) =-      PChoice qpn rdm gr       <$> (W.traverseWithKey (goP qpn) $ fmap go cs)+      PChoice qpn rdm gr       <$> W.traverseWithKey (goP qpn) (fmap go cs)     go (FChoice qfn rdm gr t m d cs) =-      FChoice qfn rdm gr t m d <$> (W.traverseWithKey (goF qfn) $ fmap go cs)+      FChoice qfn rdm gr t m d <$> W.traverseWithKey (goF qfn) (fmap go cs)     go (SChoice qsn rdm gr t     cs) =-      SChoice qsn rdm gr t     <$> (W.traverseWithKey (goS qsn) $ fmap go cs)+      SChoice qsn rdm gr t     <$> W.traverseWithKey (goS qsn) (fmap go cs)      -- For the other nodes we just recurse     go (GoalChoice rdm           cs) = GoalChoice rdm <$> T.traverse go cs
src/Distribution/Solver/Modular/Message.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ViewPatterns #-}  module Distribution.Solver.Modular.Message (     Message(..),@@ -10,14 +12,15 @@ import qualified Data.Map as M import Data.Set (Set) import qualified Data.Set as S-import Data.Maybe (catMaybes, mapMaybe)+import Data.Maybe (catMaybes, mapMaybe, isJust) import Prelude hiding (pi)  import Distribution.Pretty (prettyShow) -- from Cabal  import qualified Distribution.Solver.Modular.ConflictSet as CS import Distribution.Solver.Modular.Dependency-import Distribution.Solver.Modular.Flag+import Distribution.Solver.Modular.Flag ( QFN, QSN )+import qualified Distribution.Solver.Modular.Flag as Flag ( showQFN, showQFNBool, showQSN, showQSNBool ) import Distribution.Solver.Modular.MessageUtils          (showUnsupportedExtension, showUnsupportedLanguage) import Distribution.Solver.Modular.Package@@ -27,8 +30,10 @@ import Distribution.Solver.Types.ConstraintSource import Distribution.Solver.Types.PackagePath import Distribution.Solver.Types.Progress+import Distribution.Solver.Types.ProjectConfigPath (docProjectConfigPathFailReason) import Distribution.Types.LibraryName import Distribution.Types.UnqualComponentName+import Text.PrettyPrint (nest, render)  data Message =     Enter           -- ^ increase indentation level@@ -60,24 +65,24 @@     go !l (Step (TryP qpn i) (Step Enter (Step (Skip conflicts) (Step Leave ms)))) =         goPSkip l qpn [i] conflicts ms     go !l (Step (TryF qfn b) (Step Enter (Step (Failure c fr) (Step Leave ms)))) =-        (atLevel l $ "rejecting: " ++ showQFNBool qfn b ++ showFR c fr) (go l ms)+        (atLevel l $ blurbQFNBool Rejecting qfn b ++ showFR c fr) (go l ms)     go !l (Step (TryS qsn b) (Step Enter (Step (Failure c fr) (Step Leave ms)))) =-        (atLevel l $ "rejecting: " ++ showQSNBool qsn b ++ showFR c fr) (go l ms)+        (atLevel l $ blurbQSNBool Rejecting qsn b ++ showFR c fr) (go l ms)     go !l (Step (Next (Goal (P _  ) gr)) (Step (TryP qpn' i) ms@(Step Enter (Step (Next _) _)))) =-        (atLevel l $ "trying: " ++ showQPNPOpt qpn' i ++ showGR gr) (go l ms)+        (atLevel l $ blurbOption Trying qpn' i ++ showGR gr) (go l ms)     go !l (Step (Next (Goal (P qpn) gr)) (Step (Failure _c UnknownPackage) ms)) =-        (atLevel l $ "unknown package: " ++ showQPN qpn ++ showGR gr) $ go l ms+        atLevel l ("unknown package: " ++ showQPN qpn ++ showGR gr) $ go l ms     -- standard display     go !l (Step Enter                    ms) = go (l+1) ms     go !l (Step Leave                    ms) = go (l-1) ms-    go !l (Step (TryP qpn i)             ms) = (atLevel l $ "trying: " ++ showQPNPOpt qpn i) (go l ms)-    go !l (Step (TryF qfn b)             ms) = (atLevel l $ "trying: " ++ showQFNBool qfn b) (go l ms)-    go !l (Step (TryS qsn b)             ms) = (atLevel l $ "trying: " ++ showQSNBool qsn b) (go l ms)+    go !l (Step (TryP qpn i)             ms) = (atLevel l $ blurbOption Trying qpn i) (go l ms)+    go !l (Step (TryF qfn b)             ms) = (atLevel l $ blurbQFNBool Trying qfn b) (go l ms)+    go !l (Step (TryS qsn b)             ms) = (atLevel l $ blurbQSNBool Trying qsn b) (go l ms)     go !l (Step (Next (Goal (P qpn) gr)) ms) = (atLevel l $ showPackageGoal qpn gr) (go l ms)     go !l (Step (Next _)                 ms) = go l     ms -- ignore flag goals in the log     go !l (Step (Skip conflicts)         ms) =         -- 'Skip' should always be handled by 'goPSkip' in the case above.-        (atLevel l $ "skipping: " ++ showConflicts conflicts) (go l ms)+        (atLevel l $ blurb Skipping ++ showConflicts conflicts) (go l ms)     go !l (Step (Success)                ms) = (atLevel l $ "done") (go l ms)     go !l (Step (Failure c fr)           ms) = (atLevel l $ showFailure c fr) (go l ms) @@ -96,9 +101,12 @@               -> Progress Message a b               -> Progress String a b     goPReject l qpn is c fr (Step (TryP qpn' i) (Step Enter (Step (Failure _ fr') (Step Leave ms))))-      | qpn == qpn' && fr == fr' = goPReject l qpn (i : is) c fr ms+      | qpn == qpn' && fr == fr' =+        -- By prepending (i : is) we reverse the order of the instances.+        goPReject l qpn (i : is) c fr ms     goPReject l qpn is c fr ms =-        (atLevel l $ "rejecting: " ++ L.intercalate ", " (map (showQPNPOpt qpn) (reverse is)) ++ showFR c fr) (go l ms)+        (atLevel l $ blurbOptions Rejecting qpn (reverse is) ++ showFR c fr)+        (go l ms)      -- Handle many subsequent skipped package instances.     goPSkip :: Int@@ -108,11 +116,11 @@             -> Progress Message a b             -> Progress String a b     goPSkip l qpn is conflicts (Step (TryP qpn' i) (Step Enter (Step (Skip conflicts') (Step Leave ms))))-      | qpn == qpn' && conflicts == conflicts' = goPSkip l qpn (i : is) conflicts ms+      | qpn == qpn' && conflicts == conflicts' =+        -- By prepending (i : is) we reverse the order of the instances.+        goPSkip l qpn (i : is) conflicts ms     goPSkip l qpn is conflicts ms =-      let msg = "skipping: "-                 ++ L.intercalate ", " (map (showQPNPOpt qpn) (reverse is))-                 ++ showConflicts conflicts+      let msg = blurbOptions Skipping qpn (reverse is) ++ showConflicts conflicts       in atLevel l msg (go l ms)      -- write a message with the current level number@@ -206,12 +214,63 @@   , versionConflict :: Maybe VR   } -showQPNPOpt :: QPN -> POption -> String-showQPNPOpt qpn@(Q _pp pn) (POption i linkedTo) =+data ProgressAction =+    Trying+  | Skipping+  | Rejecting++blurb :: ProgressAction -> String+blurb = \case+  Trying -> "trying: "+  Skipping -> "skipping: "+  Rejecting -> "rejecting: "++blurbQFNBool :: ProgressAction -> QFN -> Bool -> String+blurbQFNBool a q b = blurb a ++ Flag.showQFNBool q b++blurbQSNBool :: ProgressAction -> QSN -> Bool -> String+blurbQSNBool a q b = blurb a ++ Flag.showQSNBool q b++blurbOption :: ProgressAction -> QPN -> POption -> String+blurbOption a q p = blurb a ++ showOption q p++blurbOptions :: ProgressAction -> QPN -> [POption] -> String+blurbOptions a q ps = blurb a ++ showOptions q ps++showOption :: QPN -> POption -> String+showOption qpn@(Q _pp pn) (POption i linkedTo) =   case linkedTo of     Nothing  -> showPI (PI qpn i) -- Consistent with prior to POption     Just pp' -> showQPN qpn ++ "~>" ++ showPI (PI (Q pp' pn) i) +-- | Shows a mixed list of instances and versions in a human-friendly way,+-- abbreviated.+-- >>> showOptions foobarQPN [v0, v1]+-- "foo-bar; 0, 1"+-- >>> showOptions foobarQPN [v0]+-- "foo-bar-0"+-- >>> showOptions foobarQPN [i0, i1]+-- "foo-bar; 0/installed-inplace, 1/installed-inplace"+-- >>> showOptions foobarQPN [i0, v1]+-- "foo-bar; 0/installed-inplace, 1"+-- >>> showOptions foobarQPN [v0, i1]+-- "foo-bar; 0, 1/installed-inplace"+-- >>> showOptions foobarQPN []+-- "unexpected empty list of versions"+-- >>> showOptions foobarQPN [k1, k2]+-- "foo-bar; foo-bar~>bazqux.foo-bar-1, foo-bar~>bazqux.foo-bar-2"+-- >>> showOptions foobarQPN [v0, i1, k2]+-- "foo-bar; 0, 1/installed-inplace, foo-bar~>bazqux.foo-bar-2"+showOptions :: QPN -> [POption] -> String+showOptions _ [] = "unexpected empty list of versions"+showOptions q [x] = showOption q x+showOptions q xs = showQPN q ++ "; " ++ (L.intercalate ", "+  [if isJust linkedTo+    then showOption q x+    else showI i -- Don't show the package, just the version+  | x@(POption i linkedTo) <- xs+  ])+ showGR :: QGoalReason -> String showGR UserGoal            = " (user goal)" showGR (DependencyGoal dr) = " (dependency of " ++ showDependencyReason dr ++ ")"@@ -228,12 +287,12 @@ showFR _ (PackageRequiresMissingComponent qpn comp) = " (requires " ++ showExposedComponent comp ++ " from " ++ showQPN qpn ++ ", but the component does not exist)" showFR _ (PackageRequiresPrivateComponent qpn comp) = " (requires " ++ showExposedComponent comp ++ " from " ++ showQPN qpn ++ ", but the component is private)" showFR _ (PackageRequiresUnbuildableComponent qpn comp) = " (requires " ++ showExposedComponent comp ++ " from " ++ showQPN qpn ++ ", but the component is not buildable in the current environment)"-showFR _ CannotInstall                    = " (only already installed instances can be used)" showFR _ CannotReinstall                  = " (avoiding to reinstall a package with same version but new dependencies)" showFR _ NotExplicit                      = " (not a user-provided goal nor mentioned as a constraint, but reject-unconstrained-dependencies was set)" showFR _ Shadowed                         = " (shadowed by another installed package with same version)" showFR _ (Broken u)                       = " (package is broken, missing dependency " ++ prettyShow u ++ ")" showFR _ UnknownPackage                   = " (unknown package)"+showFR _ (GlobalConstraintVersion vr (ConstraintSourceProjectConfig pc)) = '\n' : (render . nest 6 $ docProjectConfigPathFailReason vr pc) showFR _ (GlobalConstraintVersion vr src) = " (" ++ constraintSource src ++ " requires " ++ prettyShow vr ++ ")" showFR _ (GlobalConstraintInstalled src)  = " (" ++ constraintSource src ++ " requires installed instance)" showFR _ (GlobalConstraintSource src)     = " (" ++ constraintSource src ++ " requires source instance)"@@ -247,8 +306,8 @@ -- The following are internal failures. They should not occur. In the -- interest of not crashing unnecessarily, we still just print an error -- message though.-showFR _ (MalformedFlagChoice qfn)        = " (INTERNAL ERROR: MALFORMED FLAG CHOICE: " ++ showQFN qfn ++ ")"-showFR _ (MalformedStanzaChoice qsn)      = " (INTERNAL ERROR: MALFORMED STANZA CHOICE: " ++ showQSN qsn ++ ")"+showFR _ (MalformedFlagChoice qfn)        = " (INTERNAL ERROR: MALFORMED FLAG CHOICE: " ++ Flag.showQFN qfn ++ ")"+showFR _ (MalformedStanzaChoice qsn)      = " (INTERNAL ERROR: MALFORMED STANZA CHOICE: " ++ Flag.showQSN qsn ++ ")" showFR _ EmptyGoalChoice                  = " (INTERNAL ERROR: EMPTY GOAL CHOICE)"  showExposedComponent :: ExposedComponent -> String@@ -271,3 +330,17 @@                          showQPN qpn ++ componentStr ++ "==" ++ showI i        Constrained vr -> showDependencyReason dr ++ " => " ++ showQPN qpn ++                          componentStr ++ showVR vr++-- $setup+-- >>> import Distribution.Solver.Types.PackagePath+-- >>> import Distribution.Types.Version+-- >>> import Distribution.Types.UnitId+-- >>> let foobarPN = PackagePath DefaultNamespace QualToplevel+-- >>> let bazquxPN = PackagePath (Independent $ mkPackageName "bazqux") QualToplevel+-- >>> let foobarQPN = Q foobarPN (mkPackageName "foo-bar")+-- >>> let v0 = POption (I (mkVersion [0]) InRepo) Nothing+-- >>> let v1 = POption (I (mkVersion [1]) InRepo) Nothing+-- >>> let i0 = POption (I (mkVersion [0]) (Inst $ mkUnitId "foo-bar-0-inplace")) Nothing+-- >>> let i1 = POption (I (mkVersion [1]) (Inst $ mkUnitId "foo-bar-1-inplace")) Nothing+-- >>> let k1 = POption (I (mkVersion [1]) InRepo) (Just bazquxPN)+-- >>> let k2 = POption (I (mkVersion [2]) InRepo) (Just bazquxPN)
src/Distribution/Solver/Modular/Preference.hs view
@@ -12,7 +12,6 @@     , preferLinked     , preferPackagePreferences     , preferReallyEasyGoalChoices-    , requireInstalled     , onlyConstrained     , sortGoals     , pruneAfterFirstSuccess@@ -317,18 +316,6 @@        in W.mapWithKey (restrictToggling d flagConstraintValues) ts     go x                                                            = x---- | Require installed packages.-requireInstalled :: (PN -> Bool) -> EndoTreeTrav d c-requireInstalled p = go-  where-    go (PChoiceF v@(Q _ pn) rdm gr cs)-      | p pn      = PChoiceF v rdm gr (W.mapWithKey installed cs)-      | otherwise = PChoiceF v rdm gr                         cs-      where-        installed (POption (I _ (Inst _)) _) x = x-        installed _ _ = Fail (varToConflictSet (P v)) CannotInstall-    go x          = x  -- | Avoid reinstalls. --
src/Distribution/Solver/Modular/Solver.hs view
@@ -66,7 +66,6 @@   avoidReinstalls        :: AvoidReinstalls,   shadowPkgs             :: ShadowPkgs,   strongFlags            :: StrongFlags,-  allowBootLibInstalls   :: AllowBootLibInstalls,   onlyConstrained        :: OnlyConstrained,   maxBackjumps           :: Maybe Int,   enableBackjumping      :: EnableBackjumping,@@ -140,9 +139,6 @@                        validateLinking idx .                        validateTree cinfo idx pkgConfigDB     prunePhase       = (if asBool (avoidReinstalls sc) then P.avoidReinstalls (const True) else id) .-                       (if asBool (allowBootLibInstalls sc)-                        then id-                        else P.requireInstalled (`elem` nonInstallable)) .                        (case onlyConstrained sc of                           OnlyConstrainedAll ->                             P.onlyConstrained pkgIsExplicit@@ -154,23 +150,6 @@      pkgIsExplicit :: PN -> Bool     pkgIsExplicit pn = S.member pn allExplicit--    -- packages that can never be installed or upgraded-    -- If you change this enumeration, make sure to update the list in-    -- "Distribution.Client.Dependency" as well-    nonInstallable :: [PackageName]-    nonInstallable =-        L.map mkPackageName-             [ "base"-             , "ghc-bignum"-             , "ghc-prim"-             , "ghc-boot"-             , "ghc"-             , "ghci"-             , "integer-gmp"-             , "integer-simple"-             , "template-haskell"-             ]      -- When --reorder-goals is set, we use preferReallyEasyGoalChoices, which     -- prefers (keeps) goals only if the have 0 or 1 enabled choice.
src/Distribution/Solver/Modular/Tree.hs view
@@ -110,7 +110,6 @@                 | PackageRequiresMissingComponent QPN ExposedComponent                 | PackageRequiresPrivateComponent QPN ExposedComponent                 | PackageRequiresUnbuildableComponent QPN ExposedComponent-                | CannotInstall                 | CannotReinstall                 | NotExplicit                 | Shadowed
src/Distribution/Solver/Modular/Validate.hs view
@@ -1,9 +1,5 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE CPP #-}-#ifdef DEBUG_CONFLICT_SETS-{-# LANGUAGE ImplicitParams #-}-#endif module Distribution.Solver.Modular.Validate (validateTree) where  -- Validation of the tree.@@ -40,10 +36,6 @@ import Distribution.Types.LibraryName import Distribution.Types.PkgconfigVersionRange -#ifdef DEBUG_CONFLICT_SETS-import GHC.Stack (CallStack)-#endif- -- In practice, most constraints are implication constraints (IF we have made -- a number of choices, THEN we also have to ensure that). We call constraints -- that for which the preconditions are fulfilled ACTIVE. We maintain a set@@ -450,11 +442,7 @@ -- set in the sense the it contains variables that allow us to backjump -- further. We might apply some heuristics here, such as to change the -- order in which we check the constraints.-merge ::-#ifdef DEBUG_CONFLICT_SETS-  (?loc :: CallStack) =>-#endif-  MergedPkgDep -> PkgDep -> Either (ConflictSet, (ConflictingDep, ConflictingDep)) MergedPkgDep+merge :: MergedPkgDep -> PkgDep -> Either (ConflictSet, (ConflictingDep, ConflictingDep)) MergedPkgDep merge (MergedDepFixed comp1 vs1 i1) (PkgDep vs2 (PkgComponent p comp2) ci@(Fixed i2))   | i1 == i2  = Right $ MergedDepFixed comp1 vs1 i1   | otherwise =
src/Distribution/Solver/Types/ComponentDeps.hs view
@@ -24,6 +24,7 @@   , insert   , zip   , filterDeps+  , mapDeps   , fromLibraryDeps   , fromSetupDeps   , fromInstalled@@ -148,6 +149,10 @@ -- | Keep only selected components (and their associated deps info). filterDeps :: (Component -> a -> Bool) -> ComponentDeps a -> ComponentDeps a filterDeps p = ComponentDeps . Map.filterWithKey p . unComponentDeps++-- | Keep only selected components (and their associated deps info).+mapDeps :: (Component -> a -> b) -> ComponentDeps a -> ComponentDeps b+mapDeps p = ComponentDeps . Map.mapWithKey p . unComponentDeps  -- | ComponentDeps containing library dependencies only fromLibraryDeps :: a -> ComponentDeps a
src/Distribution/Solver/Types/ConstraintSource.hs view
@@ -5,7 +5,8 @@     ) where  import Distribution.Solver.Compat.Prelude-import Prelude ()+import Distribution.Solver.Types.ProjectConfigPath (ProjectConfigPath, docProjectConfigPath)+import Text.PrettyPrint (render)  -- | Source of a 'PackageConstraint'. data ConstraintSource =@@ -14,7 +15,7 @@   ConstraintSourceMainConfig FilePath    -- | Local cabal.project file-  | ConstraintSourceProjectConfig FilePath+  | ConstraintSourceProjectConfig ProjectConfigPath    -- | User config file, which is ./cabal.config by default.   | ConstraintSourceUserConfig FilePath@@ -27,7 +28,7 @@   | ConstraintSourceUserTarget    -- | Internal requirement to use installed versions of packages like ghc-prim.-  | ConstraintSourceNonUpgradeablePackage+  | ConstraintSourceNonReinstallablePackage    -- | Internal constraint used by @cabal freeze@.   | ConstraintSourceFreeze@@ -36,6 +37,10 @@   -- target, when a more specific source is not known.   | ConstraintSourceConfigFlagOrTarget +  -- | Constraint introduced by --enable-multi-repl, which requires features+  -- from Cabal >= 3.11+  | ConstraintSourceMultiRepl+   -- | The source of the constraint is not specified.   | ConstraintSourceUnknown @@ -56,15 +61,17 @@ showConstraintSource (ConstraintSourceMainConfig path) =     "main config " ++ path showConstraintSource (ConstraintSourceProjectConfig path) =-    "project config " ++ path+    "project config " ++ render (docProjectConfigPath path) showConstraintSource (ConstraintSourceUserConfig path)= "user config " ++ path showConstraintSource ConstraintSourceCommandlineFlag = "command line flag" showConstraintSource ConstraintSourceUserTarget = "user target"-showConstraintSource ConstraintSourceNonUpgradeablePackage =-    "non-upgradeable package"+showConstraintSource ConstraintSourceNonReinstallablePackage =+    "non-reinstallable package" showConstraintSource ConstraintSourceFreeze = "cabal freeze" showConstraintSource ConstraintSourceConfigFlagOrTarget =     "config file, command line flag, or user target"+showConstraintSource ConstraintSourceMultiRepl =+    "--enable-multi-repl" showConstraintSource ConstraintSourceUnknown = "unknown source" showConstraintSource ConstraintSetupCabalMinVersion =     "minimum version of Cabal used by Setup.hs"
src/Distribution/Solver/Types/PkgConfigDb.hs view
@@ -133,7 +133,7 @@     getIndividualVersion pkgConfig pkg = do        (pkgVersion, _errs, exitCode) <-                getProgramInvocationOutputAndErrors verbosity-                 (programInvocation pkgConfig ["--modversion",pkg])+                 (programInvocation pkgConfig ["--modversion", pkg])        return $ case exitCode of          ExitSuccess -> Just (pkg, pkgVersion)          _ -> Nothing
+ src/Distribution/Solver/Types/ProjectConfigPath.hs view
@@ -0,0 +1,243 @@+{-# LANGUAGE DeriveGeneric #-}++module Distribution.Solver.Types.ProjectConfigPath+    (+    -- * Project Config Path Manipulation+      ProjectConfigPath(..)+    , projectConfigPathRoot+    , nullProjectConfigPath+    , consProjectConfigPath++    -- * Messages+    , docProjectConfigPath+    , docProjectConfigPaths+    , cyclicalImportMsg+    , docProjectConfigPathFailReason++    -- * Checks and Normalization+    , isCyclicConfigPath+    , canonicalizeConfigPath+    ) where++import Distribution.Solver.Compat.Prelude hiding (toList, (<>))+import Prelude (sequence)++import Data.Coerce (coerce)+import Data.List.NonEmpty ((<|))+import Network.URI (parseURI)+import System.Directory+import System.FilePath+import qualified Data.List.NonEmpty as NE+import Distribution.Solver.Modular.Version (VR)+import Distribution.Pretty (prettyShow)+import Text.PrettyPrint++-- | Path to a configuration file, either a singleton project root, or a longer+-- list representing a path to an import.  The path is a non-empty list that we+-- build up by prepending relative imports with @consProjectConfigPath@.+--+-- An import can be a URI, such as [a stackage+-- cabal.config](https://www.stackage.org/nightly/cabal.config), but we do not+-- support URIs in the middle of the path, URIs that import other URIs, or URIs+-- that import local files.+--+-- List elements are relative to each other but once canonicalized, elements are+-- relative to the directory of the project root.+newtype ProjectConfigPath = ProjectConfigPath (NonEmpty FilePath)+    deriving (Eq, Ord, Show, Generic)++instance Binary ProjectConfigPath+instance Structured ProjectConfigPath++-- | Renders the path like this;+-- @+-- D.config+--   imported by: C.config+--   imported by: B.config+--   imported by: A.project+-- @+-- >>> render . docProjectConfigPath $ ProjectConfigPath $ "D.config" :| ["C.config", "B.config", "A.project"]+-- "D.config\n  imported by: C.config\n  imported by: B.config\n  imported by: A.project"+docProjectConfigPath :: ProjectConfigPath -> Doc+docProjectConfigPath (ProjectConfigPath (p :| [])) = text p+docProjectConfigPath (ProjectConfigPath (p :| ps)) = vcat $+    text p : [ text " " <+> text "imported by:" <+> text l | l <- ps ]++-- | Renders the paths as a list without showing which path imports another,+-- like this;+-- @+-- - cabal.project+-- - project-cabal/constraints.config+-- - project-cabal/ghc-latest.config+-- - project-cabal/ghc-options.config+-- - project-cabal/pkgs.config+-- - project-cabal/pkgs/benchmarks.config+-- - project-cabal/pkgs/buildinfo.config+-- - project-cabal/pkgs/cabal.config+-- - project-cabal/pkgs/install.config+-- - project-cabal/pkgs/integration-tests.config+-- - project-cabal/pkgs/tests.config+-- @+--+-- >>> :{+--   do+--     let ps =+--              [ ProjectConfigPath ("cabal.project" :| [])+--              , ProjectConfigPath ("project-cabal/constraints.config" :| ["cabal.project"])+--              , ProjectConfigPath ("project-cabal/ghc-latest.config" :| ["cabal.project"])+--              , ProjectConfigPath ("project-cabal/ghc-options.config" :| ["cabal.project"])+--              , ProjectConfigPath ("project-cabal/pkgs.config" :| ["cabal.project"])+--              , ProjectConfigPath ("project-cabal/pkgs/benchmarks.config" :| ["project-cabal/pkgs.config","cabal.project"])+--              , ProjectConfigPath ("project-cabal/pkgs/buildinfo.config" :| ["project-cabal/pkgs.config","cabal.project"])+--              , ProjectConfigPath ("project-cabal/pkgs/cabal.config" :| ["project-cabal/pkgs.config","cabal.project"])+--              , ProjectConfigPath ("project-cabal/pkgs/install.config" :| ["project-cabal/pkgs.config","cabal.project"])+--              , ProjectConfigPath ("project-cabal/pkgs/integration-tests.config" :| ["project-cabal/pkgs.config","cabal.project"])+--              , ProjectConfigPath ("project-cabal/pkgs/tests.config" :| ["project-cabal/pkgs.config","cabal.project"])+--              ]+--     return . render $ docProjectConfigPaths ps+-- :}+-- "- cabal.project\n- project-cabal/constraints.config\n- project-cabal/ghc-latest.config\n- project-cabal/ghc-options.config\n- project-cabal/pkgs.config\n- project-cabal/pkgs/benchmarks.config\n- project-cabal/pkgs/buildinfo.config\n- project-cabal/pkgs/cabal.config\n- project-cabal/pkgs/install.config\n- project-cabal/pkgs/integration-tests.config\n- project-cabal/pkgs/tests.config"+docProjectConfigPaths :: [ProjectConfigPath] -> Doc+docProjectConfigPaths ps = vcat+    [ text "-" <+> text p | ProjectConfigPath (p :| _) <- ps ]++-- | A message for a cyclical import, assuming the head of the path is the+-- duplicate.+cyclicalImportMsg :: ProjectConfigPath -> Doc+cyclicalImportMsg path@(ProjectConfigPath (duplicate :| _)) =+    vcat+    [ text "cyclical import of" <+> text duplicate <> semi+    , nest 2 (docProjectConfigPath path)+    ]++docProjectConfigPathFailReason :: VR -> ProjectConfigPath -> Doc+docProjectConfigPathFailReason vr pcp+    | ProjectConfigPath (p :| []) <- pcp =+        constraint p+    | ProjectConfigPath (p :| ps) <- pcp = vcat+        [ constraint p+        , cat [nest 2 $ text "imported by:" <+> text l | l <- ps ]+        ]+    where+        pathRequiresVersion p = text p <+> text "requires" <+> text (prettyShow vr)+        constraint p = parens $ text "constraint from" <+> pathRequiresVersion p++-- | The root of the path, the project itself.+projectConfigPathRoot :: ProjectConfigPath -> FilePath+projectConfigPathRoot (ProjectConfigPath xs) = last xs++-- | Used by some tests as a dummy "unused" project root.+nullProjectConfigPath :: ProjectConfigPath+nullProjectConfigPath = ProjectConfigPath $ "unused" :| []++-- | Check if the path has duplicates. A cycle of imports is not allowed. This+-- check should only be done after the path has been canonicalized with+-- @canonicalizeConfigPath@. This is because the import path may contain paths+-- that are the same in relation to their importers but different in relation to+-- the project root directory.+isCyclicConfigPath :: ProjectConfigPath -> Bool+isCyclicConfigPath (ProjectConfigPath p) = length p /= length (NE.nub p)++-- | Prepends the path of the importee to the importer path.+consProjectConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath+consProjectConfigPath p ps = ProjectConfigPath (p <| coerce ps)++-- | Make paths relative to the directory of the root of the project, not+-- relative to the file they were imported from.+makeRelativeConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath+makeRelativeConfigPath dir (ProjectConfigPath p) =+    ProjectConfigPath+    $ (\segment -> (if isURI segment then segment else makeRelative dir segment))+    <$> p++-- | Normalizes and canonicalizes a path removing '.' and '..' indirections.+-- Makes the path relative to the given directory (typically the project root)+-- instead of relative to the file it was imported from.+--+-- It converts paths like this:+-- @+-- └─ hops-0.project+--    └─ hops/hops-1.config+--       └─ ../hops-2.config+--          └─ hops/hops-3.config+--             └─ ../hops-4.config+--                └─ hops/hops-5.config+--                   └─ ../hops-6.config+--                      └─ hops/hops-7.config+--                         └─ ../hops-8.config+--                            └─ hops/hops-9.config+-- @+--+-- Into paths like this:+-- @+-- └─ hops-0.project+--    └─ hops/hops-1.config+--       └─ hops-2.config+--          └─ hops/hops-3.config+--             └─ hops-4.config+--                └─ hops/hops-5.config+--                   └─ hops-6.config+--                      └─ hops/hops-7.config+--                         └─ hops-8.config+--                            └─ hops/hops-9.config+-- @+--+-- That way we have @hops-8.config@ instead of+-- @./hops/../hops/../hops/../hops/../hops-8.config@.+--+-- Let's see how @canonicalizePath@ works that is used in the implementation+-- then we'll see how @canonicalizeConfigPath@ works.+--+-- >>> let d = testDir+-- >>> makeRelative d <$> canonicalizePath (d </> "hops/../hops/../hops/../hops/../hops-8.config")+-- "hops-8.config"+--+-- >>> let d = testDir+-- >>> p <- canonicalizeConfigPath d (ProjectConfigPath $ (d </> "hops/../hops/../hops/../hops/../hops-8.config") :| [])+-- >>> render $ docProjectConfigPath p+-- "hops-8.config"+--+-- >>> :{+--   do+--     let expected = unlines+--           [ "hops/hops-9.config"+--           , "  imported by: hops-8.config"+--           , "  imported by: hops/hops-7.config"+--           , "  imported by: hops-6.config"+--           , "  imported by: hops/hops-5.config"+--           , "  imported by: hops-4.config"+--           , "  imported by: hops/hops-3.config"+--           , "  imported by: hops-2.config"+--           , "  imported by: hops/hops-1.config"+--           , "  imported by: hops-0.project"+--           ]+--     let d = testDir+--     let configPath = ProjectConfigPath ("hops/hops-9.config" :|+--           [ "../hops-8.config"+--           , "hops/hops-7.config"+--           , "../hops-6.config"+--           , "hops/hops-5.config"+--           , "../hops-4.config"+--           , "hops/hops-3.config"+--           , "../hops-2.config"+--           , "hops/hops-1.config"+--           , d </> "hops-0.project"])+--     p <- canonicalizeConfigPath d configPath+--     return $ expected == render (docProjectConfigPath p) ++ "\n"+-- :}+-- True+canonicalizeConfigPath :: FilePath -> ProjectConfigPath -> IO ProjectConfigPath+canonicalizeConfigPath d (ProjectConfigPath p) = do+    xs <- sequence $ NE.scanr (\importee -> (>>= \importer ->+            if isURI importee+                then pure importee+                else canonicalizePath $ d </> takeDirectory importer </> importee))+            (pure ".") p+    return . makeRelativeConfigPath d . ProjectConfigPath . NE.fromList $ NE.init xs++isURI :: FilePath -> Bool+isURI = isJust . parseURI++-- $setup+-- >>> import Data.List+-- >>> testDir <- makeAbsolute =<< canonicalizePath "../cabal-testsuite/PackageTests/ConditionalAndImport"