Commit 84ed3069 authored by josh.hoyt's avatar josh.hoyt

Add an --only-dependencies flag to "install" (see ticket #697)

This flag installs only the dependencies of the packages that were
explicitly mentioned on the command line. This is useful for using
cabal-install in development environments, where the developer needs
the dependencies to build the package in development, but does not yet
want to install the package itself.
parent 8013327d
......@@ -135,7 +135,6 @@ import Distribution.Simple.BuildPaths ( exeExtension )
--TODO:
-- * add --upgrade-deps flag
-- * add --only-deps flag
-- * eliminate upgrade, replaced by --upgrade-deps and world target
-- * assign flags to packages individually
-- * complain about flags that do not apply to any package given as target
......@@ -175,14 +174,16 @@ install, upgrade
install verbosity packageDB repos comp conf
globalFlags configFlags configExFlags installFlags targets =
installWithPlanner verbosity context planner targets
installWithPlanner verbosity context (planner onlyDeps) targets
where
context :: InstallContext
context = (packageDB, repos, comp, conf,
globalFlags, configFlags, configExFlags, installFlags)
planner :: Planner
onlyDeps = fromFlag (installOnlyDeps installFlags)
planner :: Bool -> Planner
planner
| null targets = planLocalPackage verbosity
comp configFlags configExFlags
......@@ -261,8 +262,9 @@ planLocalPackage :: Verbosity
-> Compiler
-> ConfigFlags
-> ConfigExFlags
-> Bool
-> Planner
planLocalPackage verbosity comp configFlags configExFlags installed
planLocalPackage verbosity comp configFlags configExFlags onlyDeps installed
(AvailablePackageDb available availablePrefs) = do
pkg <- readPackageDescription verbosity =<< defaultPackageDesc verbosity
let -- The trick is, we add the local package to the available index and
......@@ -286,9 +288,16 @@ planLocalPackage verbosity comp configFlags configExFlags installed
preferences = mergePackagePrefs PreferLatestForSelected
availablePrefs configExFlags
return $ resolveDependenciesWithProgress buildPlatform (compilerId comp)
plan = resolveDependenciesWithProgress buildPlatform
(compilerId comp)
installed' available' preferences constraints targets
isLocalPackage = (== localPackageName) . packageName
localPackageName = packageName pkg
-- If we only want dependencies, then remove the local package from
-- the install plan after we have built it.
return $ if onlyDeps then removeFromPlan isLocalPackage plan else plan
-- | Make an 'InstallPlan' for the given dependencies.
--
......@@ -299,10 +308,11 @@ planRepoPackages :: PackagesPreferenceDefault
-> ConfigExFlags
-> InstallFlags
-> [UnresolvedDependency]
-> Bool
-> Planner
planRepoPackages defaultPref comp
globalFlags configFlags configExFlags installFlags
deps installed (AvailablePackageDb available availablePrefs) = do
deps onlyDeps installed (AvailablePackageDb available availablePrefs) = do
deps' <- addWorldPackages deps
>>= IndexUtils.disambiguateDependencies available
......@@ -316,13 +326,18 @@ planRepoPackages defaultPref comp
++ [ PackageVersionConstraint name ver
| Dependency name ver <- configConstraints configFlags ]
preferences = mergePackagePrefs defaultPref availablePrefs configExFlags
return $ resolveDependenciesWithProgress buildPlatform (compilerId comp)
plan = resolveDependenciesWithProgress buildPlatform (compilerId comp)
installed' available preferences constraints targets
return $ if onlyDeps then removeFromPlan (isGivenDep deps) plan else plan
where
hideGivenDeps pkgs index =
foldr PackageIndex.deletePackageName index
foldr PackageIndex.deletePackageName index (givenDepNames pkgs)
givenDepNames pkgs =
[ name | UnresolvedDependency (Dependency name _) _ <- pkgs ]
isGivenDep pkgs = (`elem` givenDepNames pkgs) . packageName
addWorldPackages :: [UnresolvedDependency] -> IO [UnresolvedDependency]
addWorldPackages targets = case partition World.isWorldTarget targets of
([], _) -> return targets
......@@ -337,6 +352,19 @@ planRepoPackages defaultPref comp
worldFile = fromFlag $ globalWorldFile globalFlags
-- | Adapt InstallPlan.removePackages to work on Progress so that it
-- can be integrated with the planners
--
removeFromPlan :: (InstallPlan.PlanPackage -> Bool)
-> Progress step String InstallPlan
-> Progress step String InstallPlan
removeFromPlan shouldRemove =
foldProgress Step Fail $ \plan ->
case InstallPlan.removePackages shouldRemove plan of
Right plan' -> Done plan'
Left problems ->
Fail $ unlines $ map InstallPlan.showPlanProblem problems
mergePackagePrefs :: PackagesPreferenceDefault
-> Map.Map PackageName VersionRange
-> ConfigExFlags
......
......@@ -22,6 +22,7 @@ module Distribution.Client.InstallPlan (
ready,
completed,
failed,
removePackages,
-- ** Query functions
planPlatform,
......@@ -181,6 +182,20 @@ new platform compiler index =
toList :: InstallPlan -> [PlanPackage]
toList = PackageIndex.allPackages . planIndex
-- | Remove packages from the install plan. This will result in an
-- error if there are remaining packages that depend on any matching
-- package. This is primarily useful for obtaining an install plan for
-- the dependencies of a package or set of packages without actually
-- installing the package itself, as when doing development.
--
removePackages :: (PlanPackage -> Bool) -> InstallPlan
-> Either [PlanProblem] InstallPlan
removePackages shouldRemove plan =
new (planPlatform plan) (planCompiler plan) newIdx
where
newIdx =
PackageIndex.fromList $ filter (not . shouldRemove) $ toList plan
-- | The packages that are ready to be installed. That is they are in the
-- configured state and have all their dependencies installed already.
-- The plan is complete if the result is @[]@.
......
......@@ -517,6 +517,7 @@ data InstallFlags = InstallFlags {
installReinstall :: Flag Bool,
installUpgradeDeps :: Flag Bool,
installOnly :: Flag Bool,
installOnlyDeps :: Flag Bool,
installRootCmd :: Flag String,
installSummaryFile :: [PathTemplate],
installLogFile :: Flag PathTemplate,
......@@ -533,6 +534,7 @@ defaultInstallFlags = InstallFlags {
installReinstall = Flag False,
installUpgradeDeps = Flag False,
installOnly = Flag False,
installOnlyDeps = Flag False,
installRootCmd = mempty,
installSummaryFile = mempty,
installLogFile = mempty,
......@@ -634,6 +636,12 @@ installOptions showOrParseArgs =
"Do not record the packages in the world file."
installOneShot (\v flags -> flags { installOneShot = v })
trueArg
, option [] ["only-dependencies"]
"Install only the dependencies necessary to build the listed packages"
installOnlyDeps (\v flags -> flags { installOnlyDeps = v })
trueArg
] ++ case showOrParseArgs of -- TODO: remove when "cabal install" avoids
ParseArgs ->
option [] ["only"]
......@@ -651,6 +659,7 @@ instance Monoid InstallFlags where
installReinstall = mempty,
installUpgradeDeps = mempty,
installOnly = mempty,
installOnlyDeps = mempty,
installRootCmd = mempty,
installSummaryFile = mempty,
installLogFile = mempty,
......@@ -665,6 +674,7 @@ instance Monoid InstallFlags where
installReinstall = combine installReinstall,
installUpgradeDeps = combine installUpgradeDeps,
installOnly = combine installOnly,
installOnlyDeps = combine installOnlyDeps,
installRootCmd = combine installRootCmd,
installSummaryFile = combine installSummaryFile,
installLogFile = combine installLogFile,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment