From 0fe62673056f008c58ee1ee44af9a38e6fe94ae3 Mon Sep 17 00:00:00 2001 From: Matthew Pickering <matthewtpickering@gmail.com> Date: Thu, 27 Mar 2025 13:44:02 +0000 Subject: [PATCH] Implement v2-outdated command for cabal-install This commit updates the outdated command to the new v2 architecture: - Transform the old `outdated` command into a new v2-style command `v2-outdated` - Support three modes of operation: - Check for outdated dependencies in v1-style freeze file - Check for outdated dependencies in project context (cabal.project & cabal.project.freeze) - Check for outdated dependencies in local packages Since the `cabal outdated` command now supports the v2-architecture, you can request to run the `v2-outdated` command on any target. I also introduced the `resolveTargetsFromLocalPackages` which resolves which local packages targets refer to without having to run the solver. This will be useful for `cabal check` as well. A change in behaviour from before is that the package description is flattened, so all bounds will be warned about rather than those in conditional branches being ignored. Fixes #8283 --- .../src/Distribution/Utils/Generic.hs | 5 + Cabal/src/Distribution/Simple/Utils.hs | 1 + .../Solver/Types/ProjectConfigPath.hs | 5 +- .../src/Distribution/Client/CmdBench.hs | 2 +- .../src/Distribution/Client/CmdBuild.hs | 2 +- .../src/Distribution/Client/CmdHaddock.hs | 2 +- .../Distribution/Client/CmdHaddockProject.hs | 4 +- .../src/Distribution/Client/CmdInstall.hs | 6 +- .../src/Distribution/Client/CmdListBin.hs | 2 +- .../src/Distribution/Client/CmdOutdated.hs | 490 ++++++++++-------- .../src/Distribution/Client/CmdRepl.hs | 2 +- .../src/Distribution/Client/CmdRun.hs | 2 +- .../src/Distribution/Client/CmdTarget.hs | 2 +- .../src/Distribution/Client/CmdTest.hs | 2 +- cabal-install/src/Distribution/Client/Main.hs | 2 +- .../Client/ProjectOrchestration.hs | 182 ++++++- .../Client/ProjectPlanning/Types.hs | 5 + .../src/Distribution/Client/ScriptUtils.hs | 4 +- cabal-install/tests/IntegrationTests2.hs | 8 +- .../PackageTests/Outdated/Issue8283/cabal.out | 44 ++ .../Outdated/Issue8283/cabal.project | 4 + .../Outdated/Issue8283/cabal.test.hs | 27 + .../Outdated/Issue8283/package-a/LICENSE | 28 + .../Issue8283/package-a/package-a.cabal | 24 + .../Issue8283/package-a/src/ModuleA.hs | 4 + .../Outdated/Issue8283/package-b/LICENSE | 28 + .../Issue8283/package-b/package-b.cabal | 17 + .../Issue8283/package-b/src/ModuleB.hs | 6 + .../Issue8283/repo/base-3.0.3.1/base.cabal | 154 ++++++ .../Issue8283/repo/base-3.0.3.2/base.cabal | 160 ++++++ .../Issue8283/repo/base-4.0.0.0/base.cabal | 174 +++++++ .../repo/binary-0.8.5.0/binary.cabal | 35 ++ .../repo/binary-0.8.6.0/binary.cabal | 35 ++ .../repo/binary-0.9.0.0/binary.cabal | 35 ++ .../Issue8283/repo/preferred-versions | 1 + .../template-haskell.cabal | 22 + .../template-haskell.cabal | 22 + .../template-haskell.cabal | 32 ++ .../Outdated/outdated-project-file.out | 25 +- .../Outdated/outdated-project-file.test.hs | 3 +- .../PackageTests/Outdated/outdated.out | 30 +- .../PackageTests/Outdated/outdated_freeze.out | 53 +- .../Outdated/outdated_freeze.test.hs | 2 +- cabal.project | 4 +- 44 files changed, 1400 insertions(+), 297 deletions(-) create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.out create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.project create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.test.hs create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/LICENSE create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/package-a.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/src/ModuleA.hs create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/LICENSE create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/package-b.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/src/ModuleB.hs create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.1/base.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.2/base.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-4.0.0.0/base.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.5.0/binary.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.6.0/binary.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.9.0.0/binary.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/preferred-versions create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.0/template-haskell.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.1/template-haskell.cabal create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.4.0.0/template-haskell.cabal diff --git a/Cabal-syntax/src/Distribution/Utils/Generic.hs b/Cabal-syntax/src/Distribution/Utils/Generic.hs index cc609d1264..694f4f6bd4 100644 --- a/Cabal-syntax/src/Distribution/Utils/Generic.hs +++ b/Cabal-syntax/src/Distribution/Utils/Generic.hs @@ -56,6 +56,7 @@ module Distribution.Utils.Generic , listUnion , listUnionRight , ordNub + , sortNub , ordNubBy , ordNubRight , safeHead @@ -385,6 +386,10 @@ ordNubRight = fst . foldr go ([], Set.empty) then p else (x : l, Set.insert x s) +-- | Sort and nub a list +sortNub :: Ord a => [a] -> [a] +sortNub = Set.toList . Set.fromList + -- | A right-biased version of 'listUnion'. -- -- Example: diff --git a/Cabal/src/Distribution/Simple/Utils.hs b/Cabal/src/Distribution/Simple/Utils.hs index 81763cca8f..d9109ea162 100644 --- a/Cabal/src/Distribution/Simple/Utils.hs +++ b/Cabal/src/Distribution/Simple/Utils.hs @@ -185,6 +185,7 @@ module Distribution.Simple.Utils , listUnion , listUnionRight , ordNub + , sortNub , ordNubBy , ordNubRight , safeHead diff --git a/cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs b/cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs index 17543b5f2d..a6d80dddab 100644 --- a/cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs +++ b/cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs @@ -38,7 +38,7 @@ import qualified System.FilePath.Posix as Posix import qualified System.FilePath.Windows as Windows import qualified Data.List.NonEmpty as NE import Distribution.Solver.Modular.Version (VR) -import Distribution.Pretty (prettyShow) +import Distribution.Pretty (prettyShow, Pretty(..)) import Distribution.Utils.String (trim) import Text.PrettyPrint import Distribution.Simple.Utils (ordNub) @@ -58,6 +58,9 @@ import Distribution.System (OS(Windows), buildOS) newtype ProjectConfigPath = ProjectConfigPath (NonEmpty FilePath) deriving (Eq, Show, Generic) +instance Pretty ProjectConfigPath where + pretty = docProjectConfigPath + -- | Sorts URIs after local file paths and longer file paths after shorter ones -- as measured by the number of path segments. If still equal, then sorting is -- lexical. diff --git a/cabal-install/src/Distribution/Client/CmdBench.hs b/cabal-install/src/Distribution/Client/CmdBench.hs index 0563414128..f6fc6e55d9 100644 --- a/cabal-install/src/Distribution/Client/CmdBench.hs +++ b/cabal-install/src/Distribution/Client/CmdBench.hs @@ -132,7 +132,7 @@ benchAction flags@NixStyleFlags{..} targetStrings globalFlags = do -- (as opposed to say build or haddock targets). targets <- either (reportTargetProblems verbosity) return $ - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/CmdBuild.hs b/cabal-install/src/Distribution/Client/CmdBuild.hs index e668b16532..6c8b654003 100644 --- a/cabal-install/src/Distribution/Client/CmdBuild.hs +++ b/cabal-install/src/Distribution/Client/CmdBuild.hs @@ -157,7 +157,7 @@ buildAction flags@NixStyleFlags{extraFlags = buildFlags, ..} targetStrings globa -- (as opposed to say repl or haddock targets). targets <- either (reportBuildTargetProblems verbosity) return $ - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/CmdHaddock.hs b/cabal-install/src/Distribution/Client/CmdHaddock.hs index 70e9870a07..74f10f44df 100644 --- a/cabal-install/src/Distribution/Client/CmdHaddock.hs +++ b/cabal-install/src/Distribution/Client/CmdHaddock.hs @@ -177,7 +177,7 @@ haddockAction relFlags targetStrings globalFlags = do -- haddock targets targets <- either (reportBuildDocumentationTargetProblems verbosity) return $ - resolveTargets + resolveTargetsFromSolver (selectPackageTargets haddockFlags) selectComponentTarget elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs index b2e59c3340..e69ceff308 100644 --- a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs +++ b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs @@ -28,7 +28,7 @@ import Distribution.Client.ProjectOrchestration , ProjectBuildContext (..) , TargetSelector (..) , pruneInstallPlanToTargets - , resolveTargets + , resolveTargetsFromSolver , runProjectPreBuildPhase , selectComponentTargetBasic ) @@ -146,7 +146,7 @@ haddockProjectAction flags _extraArgs globalFlags = do -- (as opposed to say repl or haddock targets). targets <- either reportTargetProblems return $ - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTargetBasic elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/CmdInstall.hs b/cabal-install/src/Distribution/Client/CmdInstall.hs index e08293dff7..a479317069 100644 --- a/cabal-install/src/Distribution/Client/CmdInstall.hs +++ b/cabal-install/src/Distribution/Client/CmdInstall.hs @@ -828,7 +828,7 @@ partitionToKnownTargetsAndHackagePackages -> IO (TargetsMap, [PackageName]) partitionToKnownTargetsAndHackagePackages verbosity pkgDb elaboratedPlan targetSelectors = do let mTargets = - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan @@ -868,7 +868,7 @@ partitionToKnownTargetsAndHackagePackages verbosity pkgDb elaboratedPlan targetS -- removed (or we've given up). targets <- either (reportBuildTargetProblems verbosity) return $ - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan @@ -888,7 +888,7 @@ constructProjectBuildContext verbosity baseCtx targetSelectors = do -- Interpret the targets on the command line as build targets targets <- either (reportBuildTargetProblems verbosity) return $ - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/CmdListBin.hs b/cabal-install/src/Distribution/Client/CmdListBin.hs index df16b98e1a..797db65c39 100644 --- a/cabal-install/src/Distribution/Client/CmdListBin.hs +++ b/cabal-install/src/Distribution/Client/CmdListBin.hs @@ -106,7 +106,7 @@ listbinAction flags@NixStyleFlags{..} args globalFlags = do -- (as opposed to say repl or haddock targets). targets <- either (reportTargetProblems verbosity) return $ - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/CmdOutdated.hs b/cabal-install/src/Distribution/Client/CmdOutdated.hs index f053c862c0..ecd6621283 100644 --- a/cabal-install/src/Distribution/Client/CmdOutdated.hs +++ b/cabal-install/src/Distribution/Client/CmdOutdated.hs @@ -1,4 +1,5 @@ -{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RecordWildCards #-} -- | @@ -13,44 +14,22 @@ module Distribution.Client.CmdOutdated , outdatedAction , ListOutdatedSettings (..) , listOutdated + , IgnoreMajorVersionBumps (..) + , showResult ) where import Distribution.Client.Compat.Prelude -import Distribution.Compat.Lens - ( _1 - , _2 - ) import Prelude () +import qualified Data.Set as Set import Distribution.Client.Config ( SavedConfig ( savedConfigureExFlags - , savedConfigureFlags - , savedGlobalFlags ) ) -import Distribution.Client.DistDirLayout - ( DistDirLayout (distProjectFile, distProjectRootDirectory) - , defaultDistDirLayout - ) -import Distribution.Client.IndexUtils as IndexUtils +import qualified Distribution.Client.IndexUtils as IndexUtils import Distribution.Client.ProjectConfig -import Distribution.Client.ProjectConfig.Legacy - ( instantiateProjectConfigSkeletonWithCompiler - ) -import Distribution.Client.ProjectFlags - ( ProjectFlags (..) - , defaultProjectFlags - , projectFlagsOptions - , removeIgnoreProjectOption - ) -import Distribution.Client.RebuildMonad - ( runRebuild - ) -import Distribution.Client.Sandbox - ( loadConfigOrSandboxConfig - ) import Distribution.Client.Sandbox.PackageEnvironment ( loadUserConfig ) @@ -60,83 +39,11 @@ import Distribution.Client.Targets , userToPackageConstraint ) import Distribution.Client.Types.SourcePackageDb as SourcePackageDb -import Distribution.Solver.Types.PackageConstraint - ( packageConstraintToDependency - ) -import Distribution.Utils.Generic - ( safeLast - , wrapText - ) - -import Distribution.Client.HttpUtils import qualified Distribution.Compat.CharParsing as P -import Distribution.Package - ( PackageName - , packageVersion - ) import Distribution.PackageDescription - ( allBuildDepends - ) import Distribution.PackageDescription.Configuration - ( finalizePD - ) -import Distribution.ReadE - ( parsecToReadE - ) -import Distribution.Simple.Command - ( CommandUI (..) - , OptionField - , ShowOrParseArgs - , liftOptionL - , optArg - , option - , reqArg - ) -import Distribution.Simple.Compiler - ( Compiler - , compilerInfo - ) -import Distribution.Simple.Flag - ( Flag - , flagToMaybe - , fromFlagOrDefault - , toFlag - ) -import Distribution.Simple.PackageDescription - ( readGenericPackageDescription - ) -import Distribution.Simple.Setup - ( optionVerbosity - , trueArg - ) -import Distribution.Simple.Utils - ( debug - , dieWithException - , notice - , tryFindPackageDesc - ) -import Distribution.System - ( Platform (..) - ) -import Distribution.Types.ComponentRequestedSpec - ( ComponentRequestedSpec (..) - ) -import Distribution.Types.Dependency - ( Dependency (..) - ) -import Distribution.Types.DependencySatisfaction - ( DependencySatisfaction (..) - ) -import Distribution.Types.PackageVersionConstraint - ( PackageVersionConstraint (..) - , simplifyPackageVersionConstraint - ) -import Distribution.Utils.NubList - ( fromNubList - ) -import Distribution.Verbosity - ( normal - , silent +import Distribution.Solver.Types.PackageConstraint + ( packageConstraintToDependency ) import Distribution.Version ( LowerBound (..) @@ -149,21 +56,44 @@ import Distribution.Version ) import qualified Data.Set as S -import Distribution.Client.Errors -import Distribution.Utils.Path (relativeSymbolicPath) +import Distribution.Client.NixStyleOptions import System.Directory - ( doesFileExist - , getCurrentDirectory + ( getCurrentDirectory ) +import Distribution.Client.ProjectOrchestration + +import Control.Monad +import Distribution.Client.ScriptUtils +import Distribution.Package +import Distribution.ReadE +import Distribution.Simple.Command +import Distribution.Simple.Flag +import Distribution.Simple.Setup hiding (GlobalFlags (..)) +import Distribution.Simple.Utils +import Distribution.Types.PackageVersionConstraint +import Distribution.Verbosity + +import qualified Data.Map.Strict as Map +import Distribution.Client.CmdErrorMessages +import Distribution.Client.ProjectPlanning.Types +import Distribution.Client.TargetProblem +import Distribution.Client.Types.PackageSpecifier +import Distribution.Solver.Types.ConstraintSource +import Distribution.Solver.Types.SourcePackage +import Distribution.Types.Component +import qualified Text.PrettyPrint as PP + +import Distribution.Client.Errors + ------------------------------------------------------------------------------- -- Command ------------------------------------------------------------------------------- -outdatedCommand :: CommandUI (ProjectFlags, OutdatedFlags) +outdatedCommand :: CommandUI (NixStyleFlags OutdatedFlags) outdatedCommand = CommandUI - { commandName = "outdated" + { commandName = "v2-outdated" , commandSynopsis = "Check for outdated dependencies." , commandDescription = Just $ \_ -> wrapText $ @@ -172,12 +102,9 @@ outdatedCommand = , commandNotes = Nothing , commandUsage = \pname -> "Usage: " ++ pname ++ " outdated [FLAGS] [PACKAGES]\n" - , commandDefaultFlags = (defaultProjectFlags, defaultOutdatedFlags) - , commandOptions = \showOrParseArgs -> - map - (liftOptionL _1) - (removeIgnoreProjectOption (projectFlagsOptions showOrParseArgs)) - ++ map (liftOptionL _2) (outdatedOptions showOrParseArgs) + , commandDefaultFlags = defaultNixStyleFlags defaultOutdatedFlags + , commandOptions = nixStyleOptions $ \showOrParseArgs -> + outdatedOptions showOrParseArgs } ------------------------------------------------------------------------------- @@ -202,8 +129,7 @@ instance Semigroup IgnoreMajorVersionBumps where IgnoreMajorVersionBumpsSome (a ++ b) data OutdatedFlags = OutdatedFlags - { outdatedVerbosity :: Flag Verbosity - , outdatedFreezeFile :: Flag Bool + { outdatedFreezeFile :: Flag Bool , outdatedNewFreezeFile :: Flag Bool , outdatedSimpleOutput :: Flag Bool , outdatedExitCode :: Flag Bool @@ -215,8 +141,7 @@ data OutdatedFlags = OutdatedFlags defaultOutdatedFlags :: OutdatedFlags defaultOutdatedFlags = OutdatedFlags - { outdatedVerbosity = toFlag normal - , outdatedFreezeFile = mempty + { outdatedFreezeFile = mempty , outdatedNewFreezeFile = mempty , outdatedSimpleOutput = mempty , outdatedExitCode = mempty @@ -227,10 +152,7 @@ defaultOutdatedFlags = outdatedOptions :: ShowOrParseArgs -> [OptionField OutdatedFlags] outdatedOptions _showOrParseArgs = - [ optionVerbosity - outdatedVerbosity - (\v flags -> flags{outdatedVerbosity = v}) - , option + [ option [] ["freeze-file", "v1-freeze-file"] "Act on the freeze file" @@ -239,8 +161,8 @@ outdatedOptions _showOrParseArgs = trueArg , option [] - ["v2-freeze-file", "new-freeze-file"] - "Act on the new-style freeze file (default: cabal.project.freeze)" + ["project-context", "v2-freeze-file", "new-freeze-file"] + "Check for outdated dependencies in the project context, for example, dependencies specified in cabal.project orcabal.project.freeze." outdatedNewFreezeFile (\v flags -> flags{outdatedNewFreezeFile = v}) trueArg @@ -307,54 +229,53 @@ outdatedOptions _showOrParseArgs = -- Action ------------------------------------------------------------------------------- --- | Entry point for the 'outdated' command. -outdatedAction :: (ProjectFlags, OutdatedFlags) -> [String] -> GlobalFlags -> IO () -outdatedAction (ProjectFlags{flagProjectDir, flagProjectFile}, OutdatedFlags{..}) _targetStrings globalFlags = do - config <- loadConfigOrSandboxConfig verbosity globalFlags - let globalFlags' = savedGlobalFlags config `mappend` globalFlags - configFlags = savedConfigureFlags config - withRepoContext verbosity globalFlags' $ \repoContext -> do - when (not newFreezeFile && (isJust mprojectDir || isJust mprojectFile)) $ - dieWithException verbosity OutdatedAction - - sourcePkgDb <- IndexUtils.getSourcePackages verbosity repoContext - (comp, platform, _progdb) <- configCompilerAux' configFlags - deps <- - if freezeFile - then depsFromFreezeFile verbosity - else - if newFreezeFile - then do - httpTransport <- - configureTransport - verbosity - (fromNubList . globalProgPathExtra $ globalFlags) - (flagToMaybe . globalHttpTransport $ globalFlags) - depsFromNewFreezeFile verbosity httpTransport comp platform mprojectDir mprojectFile - else do - depsFromPkgDesc verbosity comp platform - debug verbosity $ - "Dependencies loaded: " - ++ intercalate ", " (map prettyShow deps) - let outdatedDeps = - listOutdated - deps - sourcePkgDb - (ListOutdatedSettings ignorePred minorPred) - when (not quiet) $ - showResult verbosity outdatedDeps simpleOutput - if exitCode && (not . null $ outdatedDeps) - then exitFailure - else return () +getSourcePackages :: Verbosity -> ProjectConfig -> IO SourcePackageDb +getSourcePackages verbosity projectConfig = + projectConfigWithSolverRepoContext + verbosity + (projectConfigShared projectConfig) + (projectConfigBuildOnly projectConfig) + (\ctx -> IndexUtils.getSourcePackages verbosity ctx) + +outdatedAction :: NixStyleFlags OutdatedFlags -> [String] -> GlobalFlags -> IO () +outdatedAction flags targetStrings globalFlags = + withContextAndSelectors + AcceptNoTargets + Nothing + flags + targetStrings + globalFlags + OtherCommand + $ \_targetCtx ctx targetSelectors -> do + deps <- + if + | freezeFile -> depsFromFreezeFile verbosity + | newFreezeFile -> depsFromProjectContext verbosity (projectConfig ctx) + | otherwise -> depsFromLocalPackages verbosity ctx targetSelectors + + debug verbosity $ + "Dependencies loaded: " + ++ intercalate ", " (map prettyShow deps) + + sourcePkgDb <- getSourcePackages verbosity (projectConfig ctx) + let outdatedDeps = + listOutdated + deps + sourcePkgDb + (ListOutdatedSettings ignorePred minorPred) + when (not quiet) $ + showResult verbosity outdatedDeps simpleOutput + if exitCode && (not . null $ outdatedDeps) + then exitFailure + else return () where + OutdatedFlags{..} = extraFlags flags verbosity = if quiet then silent - else fromFlagOrDefault normal outdatedVerbosity + else fromFlagOrDefault normal (setupVerbosity (configCommonFlags (configFlags flags))) freezeFile = fromFlagOrDefault False outdatedFreezeFile newFreezeFile = fromFlagOrDefault False outdatedNewFreezeFile - mprojectDir = flagToMaybe flagProjectDir - mprojectFile = flagToMaybe flagProjectFile simpleOutput = fromFlagOrDefault False outdatedSimpleOutput quiet = fromFlagOrDefault False outdatedQuiet exitCode = fromFlagOrDefault quiet outdatedExitCode @@ -369,93 +290,153 @@ outdatedAction (ProjectFlags{flagProjectDir, flagProjectFile}, OutdatedFlags{..} let minorSet = S.fromList pkgs in \pkgname -> pkgname `S.member` minorSet +reportOutdatedTargetProblem :: Verbosity -> [TargetProblem'] -> IO a +reportOutdatedTargetProblem verbosity problems = + reportTargetProblems verbosity "check outdated dependencies for" problems + -- | Print either the list of all outdated dependencies, or a message -- that there are none. -showResult :: Verbosity -> [(PackageVersionConstraint, Version)] -> Bool -> IO () +showResult :: Verbosity -> [OutdatedDependency] -> Bool -> IO () showResult verbosity outdatedDeps simpleOutput = if not . null $ outdatedDeps then do when (not simpleOutput) $ notice verbosity "Outdated dependencies:" - for_ outdatedDeps $ \(d@(PackageVersionConstraint pn _), v) -> - let outdatedDep = - if simpleOutput - then prettyShow pn - else prettyShow d ++ " (latest: " ++ prettyShow v ++ ")" - in notice verbosity outdatedDep + if simpleOutput + then -- Simple output just prints package names, one per line + outputSimple + else -- Hierarchical output grouped by package and component + outputStructured else notice verbosity "All dependencies are up to date." + where + -- Group dependencies by package and component + groupByPackage :: [OutdatedDependency] -> [(String, [(String, [OutdatedDependency])])] + groupByPackage deps = + let + -- First, create a list of (package, component, dependency) tuples + pkgCompDeps = + [ (extractPackageName src, extractComponentName src, dep) + | dep@(OutdatedDependency _ _ src) <- deps + ] + -- Group by package + pkgGroups = + Map.fromListWith + (Map.unionWith (++)) + [ (pkg, (Map.singleton comp [d])) + | (pkg, comp, d) <- pkgCompDeps + ] + in + Map.toList (Map.map Map.toList pkgGroups) + + -- Extract package name from the source + extractPackageName :: OutdatedDependencySource -> String + extractPackageName (ConfigSource _) = "project-config" + extractPackageName (ComponentSource pkgId _) = prettyShow (pkgName pkgId) + + -- Extract component name from the source + extractComponentName :: OutdatedDependencySource -> String + extractComponentName (ConfigSource src) = showConstraintSource src + extractComponentName (ComponentSource pkgId ctarget) = showComponentTarget pkgId ctarget + + getConstraintPackageName :: PackageVersionConstraint -> PackageName + getConstraintPackageName (PackageVersionConstraint pn _) = pn + + outputSimple = + let pns = sortNub $ map (getConstraintPackageName . outdatedDependency) outdatedDeps + in for_ pns $ \pn -> + noticeNoWrap verbosity (prettyShow pn) + + outputStructured = + let + -- Group by package name, then by component + packageGroups = groupByPackage outdatedDeps + in + for_ packageGroups $ \(pkgName, componentGroups) -> do + noticeNoWrap verbosity $ "* " ++ pkgName + for_ componentGroups $ \(compName, deps) -> do + noticeNoWrap verbosity $ " - " ++ compName + for_ (sortBy (comparing (getConstraintPackageName . outdatedDependency)) deps) $ + \(OutdatedDependency d v _) -> + noticeNoWrap verbosity $ " * " ++ prettyShow d ++ " (latest: " ++ prettyShow v ++ ")" + +data OutdatedDependencyX v = OutdatedDependency + { outdatedDependency :: PackageVersionConstraint + , _outdatedVersion :: v + , _outdatedSource :: OutdatedDependencySource + } + +instance Pretty (OutdatedDependencyX Version) where + pretty (OutdatedDependency dep ver src) = + pretty dep + <+> PP.text "(latest:" + <+> pretty ver + <+> PP.text "," + <+> PP.text "from:" + <+> PP.text (prettyOutdatedDependencySource src) + <+> PP.text ")" + +instance Pretty (OutdatedDependencyX ()) where + pretty (OutdatedDependency dep _ src) = + pretty dep <+> PP.text "(from:" <+> PP.text (prettyOutdatedDependencySource src) `mappend` PP.text ")" + +data OutdatedDependencySource = ConfigSource ConstraintSource | ComponentSource PackageId ComponentTarget + +-- | Pretty print an 'OutdatedDependencySource'. +prettyOutdatedDependencySource :: OutdatedDependencySource -> String +prettyOutdatedDependencySource (ConfigSource src) = showConstraintSource src +prettyOutdatedDependencySource (ComponentSource pkgId ctarget) = prettyShow pkgId ++ ":" ++ showComponentTarget pkgId ctarget + +type CandidateOutdatedDependency = OutdatedDependencyX () + +mkCandidateOutdatedDependency :: PackageVersionConstraint -> OutdatedDependencySource -> CandidateOutdatedDependency +mkCandidateOutdatedDependency dep src = OutdatedDependency dep () src + +type OutdatedDependency = OutdatedDependencyX Version -- | Convert a list of 'UserConstraint's to a 'Dependency' list. -userConstraintsToDependencies :: [UserConstraint] -> [PackageVersionConstraint] +userConstraintsToDependencies :: [(UserConstraint, ConstraintSource)] -> [CandidateOutdatedDependency] userConstraintsToDependencies ucnstrs = - mapMaybe (packageConstraintToDependency . userToPackageConstraint) ucnstrs + mapMaybe (\(uc, src) -> fmap (flip mkCandidateOutdatedDependency (ConfigSource src)) (packageConstraintToDependency . userToPackageConstraint $ uc)) ucnstrs -- | Read the list of dependencies from the freeze file. -depsFromFreezeFile :: Verbosity -> IO [PackageVersionConstraint] +depsFromFreezeFile :: Verbosity -> IO [CandidateOutdatedDependency] depsFromFreezeFile verbosity = do cwd <- getCurrentDirectory userConfig <- loadUserConfig verbosity cwd Nothing let ucnstrs = - map fst . configExConstraints . savedConfigureExFlags $ + configExConstraints . savedConfigureExFlags $ userConfig deps = userConstraintsToDependencies ucnstrs debug verbosity "Reading the list of dependencies from the freeze file" return deps --- | Read the list of dependencies from the new-style freeze file. -depsFromNewFreezeFile :: Verbosity -> HttpTransport -> Compiler -> Platform -> Maybe FilePath -> Maybe FilePath -> IO [PackageVersionConstraint] -depsFromNewFreezeFile verbosity httpTransport compiler (Platform arch os) mprojectDir mprojectFile = do - projectRoot <- - either throwIO return - =<< findProjectRoot verbosity mprojectDir mprojectFile - let distDirLayout = - defaultDistDirLayout - projectRoot - {- TODO: Support dist dir override -} Nothing - Nothing - projectConfig <- runRebuild (distProjectRootDirectory distDirLayout) $ do - pcs <- readProjectLocalFreezeConfig verbosity httpTransport distDirLayout - pure $ instantiateProjectConfigSkeletonWithCompiler os arch (compilerInfo compiler) mempty pcs - let ucnstrs = - map fst . projectConfigConstraints . projectConfigShared $ - projectConfig +-- | Read the list of dependencies from the cabal.project context. +-- This will get dependencies from +-- * cabal.project.freeze +-- * cabal.project.local +-- * cabal.project +-- files +depsFromProjectContext :: Verbosity -> ProjectConfig -> IO [CandidateOutdatedDependency] +depsFromProjectContext verbosity projectConfig = do + let ucnstrs = projectConfigConstraints $ projectConfigShared projectConfig deps = userConstraintsToDependencies ucnstrs - freezeFile = distProjectFile distDirLayout "freeze" - freezeFileExists <- doesFileExist freezeFile - - unless freezeFileExists $ - dieWithException verbosity $ - FreezeFileExistsErr freezeFile - + provenance = projectConfigProvenance projectConfig debug verbosity $ - "Reading the list of dependencies from the new-style freeze file " ++ freezeFile + "Reading the list of dependencies from the project files: " + ++ intercalate ", " [prettyShow p | Explicit p <- Set.toList provenance] return deps -- | Read the list of dependencies from the package description. -depsFromPkgDesc :: Verbosity -> Compiler -> Platform -> IO [PackageVersionConstraint] -depsFromPkgDesc verbosity comp platform = do - path <- tryFindPackageDesc verbosity Nothing - gpd <- readGenericPackageDescription verbosity Nothing (relativeSymbolicPath path) - let cinfo = compilerInfo comp - epd = - finalizePD - mempty - (ComponentRequestedSpec True True) - (const Satisfied) - platform - cinfo - [] - gpd - case epd of - Left _ -> dieWithException verbosity FinalizePDFailed - Right (pd, _) -> do - let bd = allBuildDepends pd - debug - verbosity - "Reading the list of dependencies from the package description" - return $ map toPVC bd +depsFromPkgDesc :: Verbosity -> PackageId -> GenericPackageDescription -> ComponentTarget -> IO [CandidateOutdatedDependency] +depsFromPkgDesc verbosity pkgId gpd t@(ComponentTarget cname _subtarget) = do + let pd = flattenPackageDescription gpd + bd = targetBuildDepends (componentBuildInfo (getComponent pd cname)) + debug + verbosity + "Reading the list of dependencies from the package description" + return $ map toPVC bd where - toPVC (Dependency pn vr _) = PackageVersionConstraint pn vr + toPVC (Dependency pn vr _) = mkCandidateOutdatedDependency (PackageVersionConstraint pn vr) (ComponentSource pkgId t) -- | Various knobs for customising the behaviour of 'listOutdated'. data ListOutdatedSettings = ListOutdatedSettings @@ -467,20 +448,22 @@ data ListOutdatedSettings = ListOutdatedSettings -- | Find all outdated dependencies. listOutdated - :: [PackageVersionConstraint] + :: [CandidateOutdatedDependency] -> SourcePackageDb -> ListOutdatedSettings - -> [(PackageVersionConstraint, Version)] + -> [OutdatedDependency] listOutdated deps sourceDb (ListOutdatedSettings ignorePred minorPred) = - mapMaybe isOutdated $ map simplifyPackageVersionConstraint deps + mapMaybe isOutdated deps where - isOutdated :: PackageVersionConstraint -> Maybe (PackageVersionConstraint, Version) - isOutdated dep@(PackageVersionConstraint pname vr) + isOutdated :: CandidateOutdatedDependency -> Maybe OutdatedDependency + isOutdated (OutdatedDependency dep () src) | ignorePred pname = Nothing | otherwise = let this = map packageVersion $ SourcePackageDb.lookupDependency sourceDb pname vr latest = lookupLatest dep - in (\v -> (dep, v)) `fmap` isOutdated' this latest + in (\v -> OutdatedDependency dep v src) `fmap` isOutdated' this latest + where + PackageVersionConstraint pname vr = simplifyPackageVersionConstraint dep isOutdated' :: [Version] -> [Version] -> Maybe Version isOutdated' [] _ = Nothing @@ -506,3 +489,50 @@ listOutdated deps sourceDb (ListOutdatedSettings ignorePred minorPred) = case upper of NoUpperBound -> vr UpperBound _v1 _ -> majorBoundVersion v0 + +-- | For the outdated command, when a whole package is specified we want +-- to select all buildable components. +selectPackageTargetsForOutdated + :: TargetSelector + -> [AvailableTarget k] + -> Either (TargetProblem') [k] +selectPackageTargetsForOutdated targetSelector targets + -- No targets available at all is an error + | null targets = Left (TargetProblemNoTargets targetSelector) + -- We select all buildable components for a package + | otherwise = Right $ selectBuildableTargets targets + +-- | For the outdated command, when a specific component is specified +-- we simply select that component. +selectComponentTargetForOutdated + :: SubComponentTarget + -> AvailableTarget k + -> Either (TargetProblem') k +selectComponentTargetForOutdated subtarget target = + selectComponentTargetBasic subtarget target + +-- | Read the list of dependencies from local packages +depsFromLocalPackages :: Verbosity -> ProjectBaseContext -> [TargetSelector] -> IO [CandidateOutdatedDependency] +depsFromLocalPackages verbosity ctx targetSelectors = do + when (null targetSelectors) $ + dieWithException verbosity TargetSelectorNoTargetsInCwdTrue + targets <- + either (reportOutdatedTargetProblem verbosity) return $ + resolveTargetsFromLocalPackages + selectPackageTargetsForOutdated + selectComponentTargetForOutdated + (localPackages ctx) + targetSelectors + fmap concat <$> forM (localPackages ctx) $ \pkg -> case pkg of + SpecificSourcePackage pkg' -> do + -- Find the package in the resolved targets + let pkgId = packageId pkg' + let pkgTargets = + case Map.lookup pkgId targets of + Just componentTargets -> map fst componentTargets + Nothing -> [] + -- If no specific components were targeted, use the whole package + -- Get dependencies for each targeted component + fmap concat <$> forM pkgTargets $ \target -> + depsFromPkgDesc verbosity pkgId (srcpkgDescription pkg') target + _ -> return [] diff --git a/cabal-install/src/Distribution/Client/CmdRepl.hs b/cabal-install/src/Distribution/Client/CmdRepl.hs index ad02342e2a..6eef1221e4 100644 --- a/cabal-install/src/Distribution/Client/CmdRepl.hs +++ b/cabal-install/src/Distribution/Client/CmdRepl.hs @@ -516,7 +516,7 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g -- (as opposed to say build or haddock targets). targets <- either (reportTargetProblems verbosity) return $ - resolveTargets + resolveTargetsFromSolver (selectPackageTargets multi_repl_enabled) selectComponentTarget elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/CmdRun.hs b/cabal-install/src/Distribution/Client/CmdRun.hs index 0000a2927a..e96054fb57 100644 --- a/cabal-install/src/Distribution/Client/CmdRun.hs +++ b/cabal-install/src/Distribution/Client/CmdRun.hs @@ -228,7 +228,7 @@ runAction flags@NixStyleFlags{..} targetAndArgs globalFlags = -- (as opposed to say repl or haddock targets). targets <- either (reportTargetProblems verbosity) return $ - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/CmdTarget.hs b/cabal-install/src/Distribution/Client/CmdTarget.hs index c2edeeec89..6fc0f9f973 100644 --- a/cabal-install/src/Distribution/Client/CmdTarget.hs +++ b/cabal-install/src/Distribution/Client/CmdTarget.hs @@ -172,7 +172,7 @@ targetAction flags@NixStyleFlags{..} ts globalFlags = do targets :: TargetsMap <- either (reportBuildTargetProblems verbosity) return $ - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/CmdTest.hs b/cabal-install/src/Distribution/Client/CmdTest.hs index c839a00c44..272d5b5874 100644 --- a/cabal-install/src/Distribution/Client/CmdTest.hs +++ b/cabal-install/src/Distribution/Client/CmdTest.hs @@ -146,7 +146,7 @@ testAction flags@NixStyleFlags{..} targetStrings globalFlags = do -- (as opposed to say build or haddock targets). targets <- either (reportTargetProblems verbosity failWhenNoTestSuites) return $ - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan diff --git a/cabal-install/src/Distribution/Client/Main.hs b/cabal-install/src/Distribution/Client/Main.hs index 1a8d945611..116c682008 100644 --- a/cabal-install/src/Distribution/Client/Main.hs +++ b/cabal-install/src/Distribution/Client/Main.hs @@ -440,7 +440,6 @@ mainWorker args = do , regularCmd userConfigCommand userConfigAction , regularCmd CmdPath.pathCommand CmdPath.pathAction , regularCmd genBoundsCommand genBoundsAction - , regularCmd CmdOutdated.outdatedCommand CmdOutdated.outdatedAction , wrapperCmd hscolourCommand hscolourCommonFlags , hiddenCmd formatCommand formatAction , hiddenCmd actAsSetupCommand actAsSetupAction @@ -465,6 +464,7 @@ mainWorker args = do , newCmd CmdClean.cleanCommand CmdClean.cleanAction , newCmd CmdSdist.sdistCommand CmdSdist.sdistAction , newCmd CmdTarget.targetCommand CmdTarget.targetAction + , newCmd CmdOutdated.outdatedCommand CmdOutdated.outdatedAction , legacyCmd configureExCommand configureAction , legacyCmd buildCommand buildAction , legacyCmd replCommand replAction diff --git a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs index a14d43e4b9..9b12f57025 100644 --- a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs +++ b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs @@ -58,7 +58,8 @@ module Distribution.Client.ProjectOrchestration -- ** Selecting what targets we mean , readTargetSelectors , reportTargetSelectorProblems - , resolveTargets + , resolveTargetsFromSolver + , resolveTargetsFromLocalPackages , TargetsMap , allTargetSelectors , uniqueTargetSelectors @@ -146,6 +147,7 @@ import Distribution.Client.Types import Distribution.Solver.Types.PackageIndex ( lookupPackageName ) +import Distribution.Solver.Types.SourcePackage (SourcePackage (..)) import Distribution.Client.BuildReports.Anonymous (cabalInstallID) import qualified Distribution.Client.BuildReports.Anonymous as BuildReports @@ -169,7 +171,9 @@ import Distribution.Types.UnqualComponentName , packageNameToUnqualComponentName ) +import Distribution.PackageDescription.Configuration import Distribution.Solver.Types.OptionalStanza +import Distribution.Types.Component import Control.Exception (assert) import qualified Data.List.NonEmpty as NE @@ -564,7 +568,9 @@ runProjectPostBuildPhase -- matched this target. Typically this is exactly one, but in general it is -- possible to for different selectors to match the same target. This extra -- information is primarily to help make helpful error messages. -type TargetsMap = Map UnitId [(ComponentTarget, NonEmpty TargetSelector)] +type TargetsMap = TargetsMapX UnitId + +type TargetsMapX u = Map u [(ComponentTarget, NonEmpty TargetSelector)] -- | Get all target selectors. allTargetSelectors :: TargetsMap -> [TargetSelector] @@ -574,6 +580,63 @@ allTargetSelectors = concatMap (NE.toList . snd) . concat . Map.elems uniqueTargetSelectors :: TargetsMap -> [TargetSelector] uniqueTargetSelectors = ordNub . allTargetSelectors +-- | Resolve targets from a solver result. +-- +-- This is a convenience wrapper around 'resolveTargetsFromSolver' that takes an +-- 'ElaboratedInstallPlan' directly, rather than requiring the caller to +-- construct the 'AvailableTargetIndexes' first. +resolveTargetsFromSolver + :: forall err + . ( forall k + . TargetSelector + -> [AvailableTarget k] + -> Either (TargetProblem err) [k] + ) + -> ( forall k + . SubComponentTarget + -> AvailableTarget k + -> Either (TargetProblem err) k + ) + -> ElaboratedInstallPlan + -> Maybe (SourcePackageDb) + -> [TargetSelector] + -> Either [TargetProblem err] TargetsMap +resolveTargetsFromSolver selectPackageTargets selectComponentTarget installPlan sourceDb targetSelectors = + resolveTargets + selectPackageTargets + selectComponentTarget + (availableTargetIndexes installPlan) + sourceDb + targetSelectors + +-- | Resolve targets from local packages. +-- +-- This is a convenience wrapper around 'resolveTargets' that takes a list of +-- 'PackageSpecifier's directly, rather than requiring the caller to +-- construct the 'AvailableTargetIndexes' first. +resolveTargetsFromLocalPackages + :: forall err + . ( forall k + . TargetSelector + -> [AvailableTarget k] + -> Either (TargetProblem err) [k] + ) + -> ( forall k + . SubComponentTarget + -> AvailableTarget k + -> Either (TargetProblem err) k + ) + -> [PackageSpecifier UnresolvedSourcePackage] + -> [TargetSelector] + -> Either [TargetProblem err] (TargetsMapX PackageId) +resolveTargetsFromLocalPackages selectPackageTargets selectComponentTarget pkgSpecifiers targetSelectors = + resolveTargets + selectPackageTargets + selectComponentTarget + (availableTargetIndexesFromSourcePackages pkgSpecifiers) + Nothing + targetSelectors + -- | Given a set of 'TargetSelector's, resolve which 'UnitId's and -- 'ComponentTarget's they ought to refer to. -- @@ -606,8 +669,9 @@ uniqueTargetSelectors = ordNub . allTargetSelectors -- this commands can use 'selectComponentTargetBasic', either directly or as -- a basis for their own @selectComponentTarget@ implementation. resolveTargets - :: forall err - . ( forall k + :: forall u err + . Ord u + => ( forall k . TargetSelector -> [AvailableTarget k] -> Either (TargetProblem err) [k] @@ -617,14 +681,14 @@ resolveTargets -> AvailableTarget k -> Either (TargetProblem err) k ) - -> ElaboratedInstallPlan + -> AvailableTargetIndexes u -> Maybe (SourcePackageDb) -> [TargetSelector] - -> Either [TargetProblem err] TargetsMap + -> Either [TargetProblem err] (TargetsMapX u) resolveTargets selectPackageTargets selectComponentTarget - installPlan + AvailableTargetIndexes{..} mPkgDb = fmap mkTargetsMap . either (Left . toList) Right @@ -632,8 +696,8 @@ resolveTargets . map (\ts -> (,) ts <$> checkTarget ts) where mkTargetsMap - :: [(TargetSelector, [(UnitId, ComponentTarget)])] - -> TargetsMap + :: [(TargetSelector, [(u, ComponentTarget)])] + -> TargetsMapX u mkTargetsMap targets = Map.map nubComponentTargets $ Map.fromListWith @@ -643,9 +707,7 @@ resolveTargets , (uid, ct) <- cts ] - AvailableTargetIndexes{..} = availableTargetIndexes installPlan - - checkTarget :: TargetSelector -> Either (TargetProblem err) [(UnitId, ComponentTarget)] + checkTarget :: TargetSelector -> Either (TargetProblem err) [(u, ComponentTarget)] -- We can ask to build any whole package, project-local or a dependency checkTarget bt@(TargetPackage _ (ordNub -> [pkgid]) mkfilter) @@ -737,19 +799,19 @@ resolveTargets (\(es, xs) -> case es of [] -> Right xs; (e : es') -> Left (e :| es')) . partitionEithers -data AvailableTargetIndexes = AvailableTargetIndexes +data AvailableTargetIndexes u = AvailableTargetIndexes { availableTargetsByPackageIdAndComponentName - :: AvailableTargetsMap (PackageId, ComponentName) + :: AvailableTargetsMap (PackageId, ComponentName) u , availableTargetsByPackageId - :: AvailableTargetsMap PackageId + :: AvailableTargetsMap PackageId u , availableTargetsByPackageName - :: AvailableTargetsMap PackageName + :: AvailableTargetsMap PackageName u , availableTargetsByPackageNameAndComponentName - :: AvailableTargetsMap (PackageName, ComponentName) + :: AvailableTargetsMap (PackageName, ComponentName) u , availableTargetsByPackageNameAndUnqualComponentName - :: AvailableTargetsMap (PackageName, UnqualComponentName) + :: AvailableTargetsMap (PackageName, UnqualComponentName) u } -type AvailableTargetsMap k = Map k [AvailableTarget (UnitId, ComponentName)] +type AvailableTargetsMap k u = Map k [AvailableTarget (u, ComponentName)] -- We define a bunch of indexes to help 'resolveTargets' with resolving -- 'TargetSelector's to specific 'UnitId's. @@ -760,7 +822,7 @@ type AvailableTargetsMap k = Map k [AvailableTarget (UnitId, ComponentName)] -- -- They are all constructed lazily because they are not necessarily all used. -- -availableTargetIndexes :: ElaboratedInstallPlan -> AvailableTargetIndexes +availableTargetIndexes :: ElaboratedInstallPlan -> AvailableTargetIndexes UnitId availableTargetIndexes installPlan = AvailableTargetIndexes{..} where availableTargetsByPackageIdAndComponentName @@ -833,6 +895,86 @@ availableTargetIndexes installPlan = AvailableTargetIndexes{..} ElabPackage _ -> null (pkgComponents (elabPkgDescription pkg)) ] +-- | Create available target indexes from source packages. +-- +-- This is useful when we need to resolve targets before solver resolution. +availableTargetIndexesFromSourcePackages + :: [PackageSpecifier UnresolvedSourcePackage] -> AvailableTargetIndexes PackageId +availableTargetIndexesFromSourcePackages pkgSpecifiers = AvailableTargetIndexes{..} + where + -- Create a map of available targets from source packages + availableTargetsByPackageIdAndComponentName + :: Map (PackageId, ComponentName) [AvailableTarget (PackageId, ComponentName)] + availableTargetsByPackageIdAndComponentName = + Map.fromListWith (++) $ + concat + [ [ ((pkgId, cname), [makeAvailableTarget pkgId cname]) + | let pkgId = packageId pkg + , cname <- map componentName (pkgComponents $ flattenPackageDescription (srcpkgDescription pkg)) + ] + | SpecificSourcePackage pkg <- pkgSpecifiers + ] + + -- Helper to create an available target + makeAvailableTarget pkgId cname = + AvailableTarget + { availableTargetPackageId = pkgId + , availableTargetComponentName = cname + , availableTargetStatus = TargetBuildable (pkgId, cname) TargetRequestedByDefault + , availableTargetLocalToProject = True + } + + -- Derive other indexes from the main one, just like in availableTargetIndexes + availableTargetsByPackageId + :: Map PackageId [AvailableTarget (PackageId, ComponentName)] + availableTargetsByPackageId = + Map.mapKeysWith + (++) + (\(pkgid, _cname) -> pkgid) + availableTargetsByPackageIdAndComponentName + `Map.union` availableTargetsEmptyPackages + + -- Handle empty packages + availableTargetsEmptyPackages = + Map.fromList + [ (packageId pkg, []) + | SpecificSourcePackage pkg <- pkgSpecifiers + , null (pkgComponents (flattenPackageDescription (srcpkgDescription pkg))) + ] + + availableTargetsByPackageName + :: Map PackageName [AvailableTarget (PackageId, ComponentName)] + availableTargetsByPackageName = + Map.mapKeysWith + (++) + packageName + availableTargetsByPackageId + + availableTargetsByPackageNameAndComponentName + :: Map (PackageName, ComponentName) [AvailableTarget (PackageId, ComponentName)] + availableTargetsByPackageNameAndComponentName = + Map.mapKeysWith + (++) + (\(pkgid, cname) -> (packageName pkgid, cname)) + availableTargetsByPackageIdAndComponentName + + availableTargetsByPackageNameAndUnqualComponentName + :: Map (PackageName, UnqualComponentName) [AvailableTarget (PackageId, ComponentName)] + availableTargetsByPackageNameAndUnqualComponentName = + Map.mapKeysWith + (++) + ( \(pkgid, cname) -> + let pname = packageName pkgid + cname' = unqualComponentName pname cname + in (pname, cname') + ) + availableTargetsByPackageIdAndComponentName + where + unqualComponentName :: PackageName -> ComponentName -> UnqualComponentName + unqualComponentName pkgname = + fromMaybe (packageNameToUnqualComponentName pkgname) + . componentNameString + -- TODO: [research required] what if the solution has multiple -- versions of this package? -- e.g. due to setup deps or due to multiple independent sets diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs index 7ee5cb52f4..05aefecc77 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs @@ -57,6 +57,7 @@ module Distribution.Client.ProjectPlanning.Types , isTestComponentTarget , isBenchComponentTarget , componentOptionalStanza + , componentTargetName -- * Setup script , SetupScriptStyle (..) @@ -861,6 +862,10 @@ data ComponentTarget = ComponentTarget ComponentName SubComponentTarget instance Binary ComponentTarget instance Structured ComponentTarget +-- | Extract the component name from a 'ComponentTarget'. +componentTargetName :: ComponentTarget -> ComponentName +componentTargetName (ComponentTarget cname _) = cname + -- | Unambiguously render a 'ComponentTarget', e.g., to pass -- to a Cabal Setup script. showComponentTarget :: PackageId -> ComponentTarget -> String diff --git a/cabal-install/src/Distribution/Client/ScriptUtils.hs b/cabal-install/src/Distribution/Client/ScriptUtils.hs index 5068323e87..064eec53ad 100644 --- a/cabal-install/src/Distribution/Client/ScriptUtils.hs +++ b/cabal-install/src/Distribution/Client/ScriptUtils.hs @@ -318,13 +318,13 @@ withContextAndSelectors noTargets kind flags@NixStyleFlags{..} targetStrings glo Left (TargetSelectorNoTargetsInCwd{} : _) | [] <- targetStrings , AcceptNoTargets <- noTargets -> - return (tc, ctx, defaultTarget) + return (tc, ctx, []) Left err@(TargetSelectorNoTargetsInProject : _) -- If there are no target selectors and no targets are fine, return -- the context | [] <- targetStrings , AcceptNoTargets <- noTargets -> - return (tc, ctx, defaultTarget) + return (tc, ctx, []) | (script : _) <- targetStrings -> scriptOrError script err Left err@(TargetSelectorNoSuch t _ : _) | TargetString1 script <- t -> scriptOrError script err diff --git a/cabal-install/tests/IntegrationTests2.hs b/cabal-install/tests/IntegrationTests2.hs index 3cbb9d15b6..69c4134f14 100644 --- a/cabal-install/tests/IntegrationTests2.hs +++ b/cabal-install/tests/IntegrationTests2.hs @@ -18,7 +18,7 @@ import Distribution.Client.ProjectBuilding import Distribution.Client.ProjectConfig import Distribution.Client.ProjectOrchestration ( distinctTargetComponents - , resolveTargets + , resolveTargetsFromSolver ) import Distribution.Client.ProjectPlanning import Distribution.Client.ProjectPlanning.Types @@ -1778,7 +1778,7 @@ assertProjectDistinctTargets ++ show results where results = - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan @@ -1828,7 +1828,7 @@ assertTargetProblems elaboratedPlan selectPackageTargets selectComponentTarget = where assertTargetProblem expected targetSelector = let res = - resolveTargets + resolveTargetsFromSolver selectPackageTargets selectComponentTarget elaboratedPlan @@ -1839,7 +1839,7 @@ assertTargetProblems elaboratedPlan selectPackageTargets selectComponentTarget = problem @?= expected targetSelector unexpected -> assertFailure $ - "expected resolveTargets result: (Left [problem]) " + "expected resolveTargetsFromSolver result: (Left [problem]) " ++ "but got: " ++ show unexpected diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.out b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.out new file mode 100644 index 0000000000..08d8c0ec51 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.out @@ -0,0 +1,44 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal outdated +Configuration is affected by the following files: +- cabal.project +Outdated dependencies: +* package-a + - lib:package-a + * template-haskell >=2.3 && <2.4 (latest: 2.4.0.0) + * template-haskell >=2.3.0 && <2.3.1 (latest: 2.4.0.0) +* package-b + - lib:package-b + * base >=3.0 && <3.5 (latest: 4.0.0.0) +# cabal v2-outdated +Configuration is affected by the following files: +- cabal.project +Outdated dependencies: +* package-a + - lib:package-a + * template-haskell >=2.3 && <2.4 (latest: 2.4.0.0) + * template-haskell >=2.3.0 && <2.3.1 (latest: 2.4.0.0) +# cabal v2-outdated +Configuration is affected by the following files: +- cabal.project +base +template-haskell +# cabal v2-outdated +Configuration is affected by the following files: +- cabal.project +Outdated dependencies: +* project-config + - project config cabal.project + * base ==3.0.3.2 (latest: 4.0.0.0) +# cabal v2-outdated +Configuration is affected by the following files: +- cabal.project +Outdated dependencies: +* package-a + - lib:package-a + * template-haskell >=2.3 && <2.4 (latest: 2.4.0.0) + * template-haskell >=2.3.0 && <2.3.1 (latest: 2.4.0.0) +* package-b + - lib:package-b + * base >=3.0 && <3.5 (latest: 4.0.0.0) diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.project b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.project new file mode 100644 index 0000000000..85abdb2be1 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.project @@ -0,0 +1,4 @@ +packages: package-a + package-b + +constraints: base == 3.0.3.2 diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.test.hs b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.test.hs new file mode 100644 index 0000000000..65b9339959 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.test.hs @@ -0,0 +1,27 @@ +import Test.Cabal.Prelude +import System.Exit(ExitCode(..)) + + +main = cabalTest $ withRepo "repo" $ do + -- Test 1: Run from project root with no target specifier + result1 <- cabal' "outdated" ["all"] + assertOutputContains "package-a" result1 + assertOutputContains "package-b" result1 + + -- Test 2: Run from project root with specific package target + result2 <- cabal' "v2-outdated" ["package-a"] + assertOutputContains "package-a" result2 + assertOutputDoesNotContain "package-b" result2 + + -- Test 3: Run from project root with --simple-output flag + result3 <- cabal' "v2-outdated" ["all", "--simple-output"] + assertOutputContains "base" result3 + assertOutputContains "template-haskell" result3 + + -- Test 4: Run from subdirectory + result4 <- cabal' "v2-outdated" ["--project-context"] + assertOutputContains "base" result4 + + -- Test 6: Test exit code behavior + result6 <- fails $ cabal' "v2-outdated" ["all", "--exit-code"] + assertExitCode (ExitFailure 1) result6 diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/LICENSE b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/LICENSE new file mode 100644 index 0000000000..92316cdd64 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2023, Cabal Test Suite + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Cabal Test Suite nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/package-a.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/package-a.cabal new file mode 100644 index 0000000000..edc1301f76 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/package-a.cabal @@ -0,0 +1,24 @@ +cabal-version: 2.4 +name: package-a +version: 0.1.0.0 +synopsis: Package A for outdated command testing +license: BSD-3-Clause +license-file: LICENSE +author: Cabal Test Suite +maintainer: cabal-dev@haskell.org +build-type: Simple + +flag foo + description: test flag + +library + exposed-modules: ModuleA + build-depends: base >=3.2 && <3.3, + binary == 0.8.6.0 + if flag(foo) + build-depends: template-haskell == 2.3.0.* + else + build-depends: template-haskell == 2.3.* + + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/src/ModuleA.hs b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/src/ModuleA.hs new file mode 100644 index 0000000000..e1ed9f370a --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/src/ModuleA.hs @@ -0,0 +1,4 @@ +module ModuleA where + +simpleFunction :: Int -> Int +simpleFunction x = x + 1 diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/LICENSE b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/LICENSE new file mode 100644 index 0000000000..92316cdd64 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2023, Cabal Test Suite + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Cabal Test Suite nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/package-b.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/package-b.cabal new file mode 100644 index 0000000000..619bca806c --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/package-b.cabal @@ -0,0 +1,17 @@ +cabal-version: 2.4 +name: package-b +version: 0.1.0.0 +synopsis: Package B for outdated command testing +license: BSD-3-Clause +license-file: LICENSE +author: Cabal Test Suite +maintainer: cabal-dev@haskell.org +build-type: Simple + +library + exposed-modules: ModuleB + build-depends: base >=3.0 && < 3.5, + package-a, + binary >=0.8 && <0.8.7 + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/src/ModuleB.hs b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/src/ModuleB.hs new file mode 100644 index 0000000000..9baf7dd49b --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/src/ModuleB.hs @@ -0,0 +1,6 @@ +module ModuleB where + +import ModuleA + +anotherFunction :: Int -> Int +anotherFunction x = simpleFunction (x * 2) diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.1/base.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.1/base.cabal new file mode 100644 index 0000000000..3c7fb7a300 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.1/base.cabal @@ -0,0 +1,154 @@ +name: base +version: 3.0.3.1 +license: BSD3 +license-file: LICENSE +maintainer: libraries@haskell.org +synopsis: Basic libraries (backwards-compatibility version) +description: + This is a backwards-compatible version of the base package. + It depends on a later version of base, and was probably supplied + with your compiler when it was installed. + +cabal-version: >=1.2 +build-type: Simple + +Library { + build-depends: base >= 4.0 && < 4.2, + syb >= 0.1 && < 0.2 + extensions: PackageImports + + if impl(ghc < 6.9) { + buildable: False + } + + if impl(ghc) { + exposed-modules: + Data.Generics, + Data.Generics.Aliases, + Data.Generics.Basics, + Data.Generics.Instances, + Data.Generics.Schemes, + Data.Generics.Text, + Data.Generics.Twins, + Foreign.Concurrent, + GHC.Arr, + GHC.Base, + GHC.Conc, + GHC.ConsoleHandler, + GHC.Desugar, + GHC.Dotnet, + GHC.Enum, + GHC.Environment, + GHC.Err, + GHC.Exception, + GHC.Exts, + GHC.Float, + GHC.ForeignPtr, + GHC.Handle, + GHC.IO, + GHC.IOBase, + GHC.Int, + GHC.List, + GHC.Num, + GHC.PArr, + GHC.Pack, + GHC.Ptr, + GHC.Read, + GHC.Real, + GHC.ST, + GHC.STRef, + GHC.Show, + GHC.Stable, + GHC.Storable, + GHC.TopHandler, + GHC.Unicode, + GHC.Weak, + GHC.Word, + System.Timeout + } + exposed-modules: + Control.Applicative, + Control.Arrow, + Control.Category, + Control.Concurrent, + Control.Concurrent.Chan, + Control.Concurrent.MVar, + Control.Concurrent.QSem, + Control.Concurrent.QSemN, + Control.Concurrent.SampleVar, + Control.Exception, + Control.Monad, + Control.Monad.Fix, + Control.Monad.Instances, + Control.Monad.ST, + Control.Monad.ST.Lazy, + Control.Monad.ST.Strict, + Data.Bits, + Data.Bool, + Data.Char, + Data.Complex, + Data.Dynamic, + Data.Either, + Data.Eq, + Data.Fixed, + Data.Foldable + Data.Function, + Data.HashTable, + Data.IORef, + Data.Int, + Data.Ix, + Data.List, + Data.Maybe, + Data.Monoid, + Data.Ord, + Data.Ratio, + Data.STRef, + Data.STRef.Lazy, + Data.STRef.Strict, + Data.String, + Data.Traversable + Data.Tuple, + Data.Typeable, + Data.Unique, + Data.Version, + Data.Word, + Debug.Trace, + Foreign, + Foreign.C, + Foreign.C.Error, + Foreign.C.String, + Foreign.C.Types, + Foreign.ForeignPtr, + Foreign.Marshal, + Foreign.Marshal.Alloc, + Foreign.Marshal.Array, + Foreign.Marshal.Error, + Foreign.Marshal.Pool, + Foreign.Marshal.Utils, + Foreign.Ptr, + Foreign.StablePtr, + Foreign.Storable, + Numeric, + Prelude, + System.Console.GetOpt, + System.CPUTime, + System.Environment, + System.Exit, + System.IO, + System.IO.Error, + System.IO.Unsafe, + System.Info, + System.Mem, + System.Mem.StableName, + System.Mem.Weak, + System.Posix.Internals, + System.Posix.Types, + Text.ParserCombinators.ReadP, + Text.ParserCombinators.ReadPrec, + Text.Printf, + Text.Read, + Text.Read.Lex, + Text.Show, + Text.Show.Functions + Unsafe.Coerce +} diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.2/base.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.2/base.cabal new file mode 100644 index 0000000000..1edd58ea0c --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.2/base.cabal @@ -0,0 +1,160 @@ +name: base +version: 3.0.3.2 +license: BSD3 +license-file: LICENSE +maintainer: libraries@haskell.org +bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries/base +synopsis: Basic libraries (backwards-compatibility version) +description: + This is a backwards-compatible version of the base package. + It depends on a later version of base, and was probably supplied + with your compiler when it was installed. + +cabal-version: >=1.6 +build-type: Simple + +source-repository head + type: darcs + location: http://darcs.haskell.org/packages/base3-compat + +Library { + build-depends: base >= 4.0 && < 4.3, + syb >= 0.1 && < 0.2 + extensions: PackageImports,CPP + ghc-options: -fno-warn-deprecations + + if impl(ghc < 6.9) { + buildable: False + } + + if impl(ghc) { + exposed-modules: + Data.Generics, + Data.Generics.Aliases, + Data.Generics.Basics, + Data.Generics.Instances, + Data.Generics.Schemes, + Data.Generics.Text, + Data.Generics.Twins, + Foreign.Concurrent, + GHC.Arr, + GHC.Base, + GHC.Conc, + GHC.ConsoleHandler, + GHC.Desugar, + GHC.Dotnet, + GHC.Enum, + GHC.Environment, + GHC.Err, + GHC.Exception, + GHC.Exts, + GHC.Float, + GHC.ForeignPtr, + GHC.Handle, + GHC.IO, + GHC.IOBase, + GHC.Int, + GHC.List, + GHC.Num, + GHC.PArr, + GHC.Pack, + GHC.Ptr, + GHC.Read, + GHC.Real, + GHC.ST, + GHC.STRef, + GHC.Show, + GHC.Stable, + GHC.Storable, + GHC.TopHandler, + GHC.Unicode, + GHC.Weak, + GHC.Word, + System.Timeout + } + exposed-modules: + Control.Applicative, + Control.Arrow, + Control.Category, + Control.Concurrent, + Control.Concurrent.Chan, + Control.Concurrent.MVar, + Control.Concurrent.QSem, + Control.Concurrent.QSemN, + Control.Concurrent.SampleVar, + Control.Exception, + Control.Monad, + Control.Monad.Fix, + Control.Monad.Instances, + Control.Monad.ST, + Control.Monad.ST.Lazy, + Control.Monad.ST.Strict, + Data.Bits, + Data.Bool, + Data.Char, + Data.Complex, + Data.Dynamic, + Data.Either, + Data.Eq, + Data.Fixed, + Data.Foldable + Data.Function, + Data.HashTable, + Data.IORef, + Data.Int, + Data.Ix, + Data.List, + Data.Maybe, + Data.Monoid, + Data.Ord, + Data.Ratio, + Data.STRef, + Data.STRef.Lazy, + Data.STRef.Strict, + Data.String, + Data.Traversable + Data.Tuple, + Data.Typeable, + Data.Unique, + Data.Version, + Data.Word, + Debug.Trace, + Foreign, + Foreign.C, + Foreign.C.Error, + Foreign.C.String, + Foreign.C.Types, + Foreign.ForeignPtr, + Foreign.Marshal, + Foreign.Marshal.Alloc, + Foreign.Marshal.Array, + Foreign.Marshal.Error, + Foreign.Marshal.Pool, + Foreign.Marshal.Utils, + Foreign.Ptr, + Foreign.StablePtr, + Foreign.Storable, + Numeric, + Prelude, + System.Console.GetOpt, + System.CPUTime, + System.Environment, + System.Exit, + System.IO, + System.IO.Error, + System.IO.Unsafe, + System.Info, + System.Mem, + System.Mem.StableName, + System.Mem.Weak, + System.Posix.Internals, + System.Posix.Types, + Text.ParserCombinators.ReadP, + Text.ParserCombinators.ReadPrec, + Text.Printf, + Text.Read, + Text.Read.Lex, + Text.Show, + Text.Show.Functions + Unsafe.Coerce +} diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-4.0.0.0/base.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-4.0.0.0/base.cabal new file mode 100644 index 0000000000..1aa8333373 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-4.0.0.0/base.cabal @@ -0,0 +1,174 @@ +name: base +version: 4.0.0.0 +license: BSD3 +license-file: LICENSE +maintainer: libraries@haskell.org +synopsis: Basic libraries +description: + This package contains the Prelude and its support libraries, + and a large collection of useful libraries ranging from data + structures to parsing combinators and debugging utilities. +cabal-version: >= 1.2.3 +build-type: Configure +extra-tmp-files: + config.log config.status autom4te.cache + include/HsBaseConfig.h +extra-source-files: + config.guess config.sub install-sh + aclocal.m4 configure.ac configure + include/CTypes.h + +Library { + if impl(ghc) { + build-depends: rts, ghc-prim, integer + exposed-modules: + Foreign.Concurrent, + GHC.Arr, + GHC.Base, + GHC.Classes, + GHC.Conc, + GHC.ConsoleHandler, + GHC.Desugar, + GHC.Enum, + GHC.Environment, + GHC.Err, + GHC.Exception, + GHC.Exts, + GHC.Float, + GHC.ForeignPtr, + GHC.Handle, + GHC.IO, + GHC.IOBase, + GHC.Int, + GHC.List, + GHC.Num, + GHC.PArr, + GHC.Pack, + GHC.Ptr, + GHC.Read, + GHC.Real, + GHC.ST, + GHC.STRef, + GHC.Show, + GHC.Stable, + GHC.Storable, + GHC.TopHandler, + GHC.Unicode, + GHC.Weak, + GHC.Word, + System.Timeout + extensions: MagicHash, ExistentialQuantification, Rank2Types, + ScopedTypeVariables, UnboxedTuples, + ForeignFunctionInterface, UnliftedFFITypes, + DeriveDataTypeable, GeneralizedNewtypeDeriving, + FlexibleInstances, PatternSignatures, StandaloneDeriving, + PatternGuards, EmptyDataDecls + } + exposed-modules: + Control.Applicative, + Control.Arrow, + Control.Category, + Control.Concurrent, + Control.Concurrent.Chan, + Control.Concurrent.MVar, + Control.Concurrent.QSem, + Control.Concurrent.QSemN, + Control.Concurrent.SampleVar, + Control.Exception, + Control.Exception.Base + Control.OldException, + Control.Monad, + Control.Monad.Fix, + Control.Monad.Instances, + Control.Monad.ST + Control.Monad.ST.Lazy + Control.Monad.ST.Strict + Data.Bits, + Data.Bool, + Data.Char, + Data.Complex, + Data.Dynamic, + Data.Either, + Data.Eq, + Data.Data, + Data.Fixed, + Data.Foldable + Data.Function, + Data.HashTable, + Data.IORef, + Data.Int, + Data.Ix, + Data.List, + Data.Maybe, + Data.Monoid, + Data.Ord, + Data.Ratio, + Data.STRef + Data.STRef.Lazy + Data.STRef.Strict + Data.String, + Data.Traversable + Data.Tuple, + Data.Typeable, + Data.Unique, + Data.Version, + Data.Word, + Debug.Trace, + Foreign, + Foreign.C, + Foreign.C.Error, + Foreign.C.String, + Foreign.C.Types, + Foreign.ForeignPtr, + Foreign.Marshal, + Foreign.Marshal.Alloc, + Foreign.Marshal.Array, + Foreign.Marshal.Error, + Foreign.Marshal.Pool, + Foreign.Marshal.Utils, + Foreign.Ptr, + Foreign.StablePtr, + Foreign.Storable, + Numeric, + Prelude, + System.Console.GetOpt + System.CPUTime, + System.Environment, + System.Exit, + System.IO, + System.IO.Error, + System.IO.Unsafe, + System.Info, + System.Mem, + System.Mem.StableName, + System.Mem.Weak, + System.Posix.Internals, + System.Posix.Types, + Text.ParserCombinators.ReadP, + Text.ParserCombinators.ReadPrec, + Text.Printf, + Text.Read, + Text.Read.Lex, + Text.Show, + Text.Show.Functions + Unsafe.Coerce + c-sources: + cbits/PrelIOUtils.c + cbits/WCsubst.c + cbits/Win32Utils.c + cbits/consUtils.c + cbits/dirUtils.c + cbits/inputReady.c + cbits/selectUtils.c + include-dirs: include + includes: HsBase.h + install-includes: HsBase.h HsBaseConfig.h WCsubst.h dirUtils.h consUtils.h Typeable.h + if os(windows) { + extra-libraries: wsock32, msvcrt, kernel32, user32, shell32 + } + extensions: CPP + -- We need to set the package name to base (without a version number) + -- as it's magic. + ghc-options: -package-name base + nhc98-options: -H4M -K3M +} diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.5.0/binary.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.5.0/binary.cabal new file mode 100644 index 0000000000..b0ab2b24ec --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.5.0/binary.cabal @@ -0,0 +1,35 @@ +name: binary +version: 0.8.5.0 +license: BSD3 +license-file: LICENSE +author: Lennart Kolmodin <kolmodin@gmail.com> +maintainer: Lennart Kolmodin, Don Stewart <dons00@gmail.com> +homepage: https://github.com/kolmodin/binary +description: Efficient, pure binary serialisation using lazy ByteStrings. + Haskell values may be encoded to and from binary formats, + written to disk as binary, or sent over the network. + The format used can be automatically generated, or + you can choose to implement a custom format if needed. + Serialisation speeds of over 1 G\/sec have been observed, + so this library should be suitable for high performance + scenarios. +synopsis: Binary serialisation for Haskell values using lazy ByteStrings +category: Data, Parsing +stability: provisional +build-type: Simple +cabal-version: >= 1.8 + +library + build-depends: base >= 3 && < 5, bytestring >= 0.8.4, containers, array + hs-source-dirs: src + exposed-modules: Data.Binary, + Data.Binary.Put, + Data.Binary.Get, + Data.Binary.Get.Internal, + Data.Binary.Builder + + other-modules: Data.Binary.Class, + Data.Binary.Internal, + Data.Binary.Generic, + Data.Binary.FloatCast + ghc-options: -O2 -Wall -fliberate-case-threshold=1000 diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.6.0/binary.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.6.0/binary.cabal new file mode 100644 index 0000000000..caa10cb223 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.6.0/binary.cabal @@ -0,0 +1,35 @@ +name: binary +version: 0.8.6.0 +license: BSD3 +license-file: LICENSE +author: Lennart Kolmodin <kolmodin@gmail.com> +maintainer: Lennart Kolmodin, Don Stewart <dons00@gmail.com> +homepage: https://github.com/kolmodin/binary +description: Efficient, pure binary serialisation using lazy ByteStrings. + Haskell values may be encoded to and from binary formats, + written to disk as binary, or sent over the network. + The format used can be automatically generated, or + you can choose to implement a custom format if needed. + Serialisation speeds of over 1 G\/sec have been observed, + so this library should be suitable for high performance + scenarios. +synopsis: Binary serialisation for Haskell values using lazy ByteStrings +category: Data, Parsing +stability: provisional +build-type: Simple +cabal-version: >= 1.8 + +library + build-depends: base >= 3 && < 5, bytestring >= 0.8.4, containers, array + hs-source-dirs: src + exposed-modules: Data.Binary, + Data.Binary.Put, + Data.Binary.Get, + Data.Binary.Get.Internal, + Data.Binary.Builder + + other-modules: Data.Binary.Class, + Data.Binary.Internal, + Data.Binary.Generic, + Data.Binary.FloatCast + ghc-options: -O2 -Wall -fliberate-case-threshold=1000 diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.9.0.0/binary.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.9.0.0/binary.cabal new file mode 100644 index 0000000000..66485f6f76 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.9.0.0/binary.cabal @@ -0,0 +1,35 @@ +name: binary +version: 0.9.0.0 +license: BSD3 +license-file: LICENSE +author: Lennart Kolmodin <kolmodin@gmail.com> +maintainer: Lennart Kolmodin, Don Stewart <dons00@gmail.com> +homepage: https://github.com/kolmodin/binary +description: Efficient, pure binary serialisation using lazy ByteStrings. + Haskell values may be encoded to and from binary formats, + written to disk as binary, or sent over the network. + The format used can be automatically generated, or + you can choose to implement a custom format if needed. + Serialisation speeds of over 1 G\/sec have been observed, + so this library should be suitable for high performance + scenarios. +synopsis: Binary serialisation for Haskell values using lazy ByteStrings +category: Data, Parsing +stability: provisional +build-type: Simple +cabal-version: >= 1.8 + +library + build-depends: base >= 3 && < 5, bytestring >= 0.8.4, containers, array + hs-source-dirs: src + exposed-modules: Data.Binary, + Data.Binary.Put, + Data.Binary.Get, + Data.Binary.Get.Internal, + Data.Binary.Builder + + other-modules: Data.Binary.Class, + Data.Binary.Internal, + Data.Binary.Generic, + Data.Binary.FloatCast + ghc-options: -O2 -Wall -fliberate-case-threshold=1000 diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/preferred-versions b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/preferred-versions new file mode 100644 index 0000000000..5be791d3d0 --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/preferred-versions @@ -0,0 +1 @@ +binary <0.9.0.0 || >0.9.0.0 diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.0/template-haskell.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.0/template-haskell.cabal new file mode 100644 index 0000000000..064cb9d51b --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.0/template-haskell.cabal @@ -0,0 +1,22 @@ +name: template-haskell +version: 2.3.0.0 +x-revision: 1 +license: BSD3 +license-file: LICENSE +maintainer: libraries@haskell.org +description: + Facilities for manipulating Haskell source code using Template Haskell. +build-type: Simple +build-depends: base<4.3, pretty, packedstring, containers +exposed-modules: + Language.Haskell.TH.Syntax, + Language.Haskell.TH.PprLib, + Language.Haskell.TH.Ppr, + Language.Haskell.TH.Lib, + Language.Haskell.TH.Quote, + Language.Haskell.TH +extensions: MagicHash, PatternGuards, PolymorphicComponents, + DeriveDataTypeable, TypeSynonymInstances +-- We need to set the package name to template-haskell (without a +-- version number) as it's magic. +ghc-options: -package-name template-haskell diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.1/template-haskell.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.1/template-haskell.cabal new file mode 100644 index 0000000000..8fbe6b269a --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.1/template-haskell.cabal @@ -0,0 +1,22 @@ +name: template-haskell +version: 2.3.0.1 +x-revision: 1 +license: BSD3 +license-file: LICENSE +maintainer: libraries@haskell.org +description: + Facilities for manipulating Haskell source code using Template Haskell. +build-type: Simple +build-depends: base <4.3, pretty, packedstring, containers +exposed-modules: + Language.Haskell.TH.Syntax, + Language.Haskell.TH.PprLib, + Language.Haskell.TH.Ppr, + Language.Haskell.TH.Lib, + Language.Haskell.TH.Quote, + Language.Haskell.TH +extensions: MagicHash, PatternGuards, PolymorphicComponents, + DeriveDataTypeable, TypeSynonymInstances +-- We need to set the package name to template-haskell (without a +-- version number) as it's magic. +ghc-options: -package-name template-haskell diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.4.0.0/template-haskell.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.4.0.0/template-haskell.cabal new file mode 100644 index 0000000000..4c5ee3cf3a --- /dev/null +++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.4.0.0/template-haskell.cabal @@ -0,0 +1,32 @@ +name: template-haskell +version: 2.4.0.0 +x-revision: 1 +license: BSD3 +license-file: LICENSE +maintainer: libraries@haskell.org +bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=Template%20Haskell +description: + Facilities for manipulating Haskell source code using Template Haskell. +build-type: Simple +Cabal-Version: >= 1.6 + +Library + build-depends: base >= 3 && < 4.3, + pretty, containers + exposed-modules: + Language.Haskell.TH.Syntax.Internals + Language.Haskell.TH.Syntax + Language.Haskell.TH.PprLib + Language.Haskell.TH.Ppr + Language.Haskell.TH.Lib + Language.Haskell.TH.Quote + Language.Haskell.TH + extensions: MagicHash, PatternGuards, PolymorphicComponents, + DeriveDataTypeable, TypeSynonymInstances + -- We need to set the package name to template-haskell (without a + -- version number) as it's magic. + ghc-options: -package-name template-haskell + +source-repository head + type: darcs + location: http://darcs.haskell.org/packages/template-haskell/ diff --git a/cabal-testsuite/PackageTests/Outdated/outdated-project-file.out b/cabal-testsuite/PackageTests/Outdated/outdated-project-file.out index 186bab610c..82fedb3671 100644 --- a/cabal-testsuite/PackageTests/Outdated/outdated-project-file.out +++ b/cabal-testsuite/PackageTests/Outdated/outdated-project-file.out @@ -1,11 +1,28 @@ # cabal v2-update Downloading the latest package list from test-local-repo # cabal outdated +Configuration is affected by the following files: +- variant.project +- variant.project.freeze Outdated dependencies: -base ==3.0.3.2 (latest: 4.0.0.0) +* project-config + - project config variant.project.freeze + * base ==3.0.3.2 (latest: 4.0.0.0) # cabal outdated +Configuration is affected by the following files: +- variant.project +- variant.project.freeze Outdated dependencies: -base ==3.0.3.2 (latest: 4.0.0.0) +* project-config + - project config variant.project.freeze + * base ==3.0.3.2 (latest: 4.0.0.0) # cabal outdated -Error: [Cabal-7103] ---project-dir and --project-file must only be used with --v2-freeze-file. +Configuration is affected by the following files: +- variant.project +- variant.project.freeze +Outdated dependencies: +* my + - lib:my + * base >=3 && <4 (latest: 4.0.0.0) + - test:tests-Foo + * template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0) diff --git a/cabal-testsuite/PackageTests/Outdated/outdated-project-file.test.hs b/cabal-testsuite/PackageTests/Outdated/outdated-project-file.test.hs index 84c2a1d58c..6dbce3d264 100644 --- a/cabal-testsuite/PackageTests/Outdated/outdated-project-file.test.hs +++ b/cabal-testsuite/PackageTests/Outdated/outdated-project-file.test.hs @@ -11,5 +11,4 @@ main = cabalTest $ withRepo "repo" $ do assertOutputDoesNotContain "template-haskell" res assertOutputDoesNotContain "binary" res - -- Test for erroring on --project-file without --v2-freeze-file - fails $ cabal "outdated" ["--project-file", "variant.project"] + cabal "outdated" ["--project-file", "variant.project"] diff --git a/cabal-testsuite/PackageTests/Outdated/outdated.out b/cabal-testsuite/PackageTests/Outdated/outdated.out index b11fae3c32..ba11ee4243 100644 --- a/cabal-testsuite/PackageTests/Outdated/outdated.out +++ b/cabal-testsuite/PackageTests/Outdated/outdated.out @@ -1,16 +1,38 @@ # cabal v2-update Downloading the latest package list from test-local-repo # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze Outdated dependencies: -base >=3 && <4 (latest: 4.0.0.0) -template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0) +* my + - lib:my + * base >=3 && <4 (latest: 4.0.0.0) + - test:tests-Foo + * template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0) # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze Outdated dependencies: -template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0) +* my + - test:tests-Foo + * template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0) # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze All dependencies are up to date. # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze Outdated dependencies: -template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0) +* my + - test:tests-Foo + * template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0) # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze All dependencies are up to date. diff --git a/cabal-testsuite/PackageTests/Outdated/outdated_freeze.out b/cabal-testsuite/PackageTests/Outdated/outdated_freeze.out index d417b8dfe7..bf0a44ada6 100644 --- a/cabal-testsuite/PackageTests/Outdated/outdated_freeze.out +++ b/cabal-testsuite/PackageTests/Outdated/outdated_freeze.out @@ -1,29 +1,54 @@ # cabal v2-update Downloading the latest package list from test-local-repo # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze Outdated dependencies: -base ==3.0.3.2 (latest: 4.0.0.0) -template-haskell ==2.3.0.0 (latest: 2.4.0.0) -binary ==0.8.5.0 (latest: 0.8.6.0) +* project-config + - project config cabal.project.freeze + * base ==3.0.3.2 (latest: 4.0.0.0) + * binary ==0.8.5.0 (latest: 0.8.6.0) + * template-haskell ==2.3.0.0 (latest: 2.4.0.0) # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze All dependencies are up to date. # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze Outdated dependencies: -template-haskell ==2.3.0.0 (latest: 2.3.0.1) -binary ==0.8.5.0 (latest: 0.8.6.0) +* project-config + - project config cabal.project.freeze + * binary ==0.8.5.0 (latest: 0.8.6.0) + * template-haskell ==2.3.0.0 (latest: 2.3.0.1) # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze Outdated dependencies: -base ==3.0.3.2 (latest: 4.0.0.0) -template-haskell ==2.3.0.0 (latest: 2.4.0.0) -binary ==0.8.5.0 (latest: 0.8.6.0) +* project-config + - user config <ROOT>/cabal.config + * base ==3.0.3.2 (latest: 4.0.0.0) + * binary ==0.8.5.0 (latest: 0.8.6.0) + * template-haskell ==2.3.0.0 (latest: 2.4.0.0) # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze All dependencies are up to date. # cabal outdated +Configuration is affected by the following files: +- cabal.project +- cabal.project.freeze Outdated dependencies: -template-haskell ==2.3.0.0 (latest: 2.3.0.1) -binary ==0.8.5.0 (latest: 0.8.6.0) +* project-config + - user config <ROOT>/cabal.config + * binary ==0.8.5.0 (latest: 0.8.6.0) + * template-haskell ==2.3.0.0 (latest: 2.3.0.1) # cabal outdated -Error: [Cabal-7104] -Couldn't find a freeze file expected at: <ROOT>/cabal.project.missing.freeze.freeze - -We are looking for this file because you supplied '--project-file' or '--v2-freeze-file'. When one of these flags is given, we try to read the dependencies from a freeze file. If it is undesired behaviour, you should not use these flags, otherwise please generate a freeze file via 'cabal freeze'. +Configuration is affected by the following files: +- cabal.project.missing.freeze +All dependencies are up to date. diff --git a/cabal-testsuite/PackageTests/Outdated/outdated_freeze.test.hs b/cabal-testsuite/PackageTests/Outdated/outdated_freeze.test.hs index 35756590ea..175b74d7b3 100644 --- a/cabal-testsuite/PackageTests/Outdated/outdated_freeze.test.hs +++ b/cabal-testsuite/PackageTests/Outdated/outdated_freeze.test.hs @@ -19,5 +19,5 @@ main = cabalTest $ withRepo "repo" $ do assertOutputContains "template-haskell" out assertOutputContains "binary" out) - fails $ cabal' "outdated" ["--project-file=cabal.project.missing.freeze", "--v2-freeze-file"] + cabal' "outdated" ["--project-file=cabal.project.missing.freeze", "--v2-freeze-file"] return () diff --git a/cabal.project b/cabal.project index a2075cfdc2..21f5af4a09 100644 --- a/cabal.project +++ b/cabal.project @@ -3,7 +3,9 @@ import: project-cabal/ghc-latest.config import: project-cabal/pkgs.config import: project-cabal/constraints.config -tests: True +tests: False + +multi-repl: True -- if you are developing on a system without TH, use a `cabal.project.local` -- to disable this -- GitLab