Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions cabal-install/src/Distribution/Client/CmdInstall.hs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ import Distribution.Package
( Package (..)
, PackageName
, mkPackageName
, packageName
, unPackageName
)
import Distribution.Simple.BuildPaths
Expand Down Expand Up @@ -775,13 +776,19 @@ getSpecsAndTargetSelectors verbosity reducedVerbosity sourcePkgDb targetSelector

localPkgs = sdistize <$> localPackages baseCtx

gatherTargets :: UnitId -> TargetSelector
gatherTargets targetId = TargetPackageNamed pkgName targetFilter
where
targetUnit = Map.findWithDefault (error "cannot find target unit") targetId planMap
PackageIdentifier{..} = packageId targetUnit

localTargets = map gatherTargets (Map.keys targetsMap)
localTargets =
ordNub
[ gatherTarget pkgName ts
| (unitId, components) <- Map.toList targetsMap
, let pkgName = packageName (planMap Map.! unitId)
, (_, selectors) <- components
, ts <- NE.toList selectors
]

gatherTarget pkgName ts = case ts of
TargetComponent{} -> ts
TargetComponentUnknown{} -> ts
_ -> TargetPackageNamed pkgName targetFilter

hackagePkgs :: [PackageSpecifier UnresolvedSourcePackage]
hackagePkgs = [NamedPackage pn [] | pn <- hackageNames]
Expand Down
1 change: 1 addition & 0 deletions cabal-testsuite/PackageTests/Install/T8614/cabal.project
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
21 changes: 21 additions & 0 deletions cabal-testsuite/PackageTests/Install/T8614/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Test.Cabal.Prelude

import System.Directory (doesFileExist)
import System.FilePath ((<.>), (</>))

-- Test that `cabal install <exe>` installs only the named executable,
-- not every executable in the package. See #8614.
main = cabalTest $ do
env <- getTestEnv
recordMode DoNotRecord $ do
let installdir = testPrefixDir env </> "bin"
exeExt = if isWindows then "exe" else ""

cabal "install"
["example1", "--installdir", installdir, "--overwrite-policy=always"]

example1Installed <- liftIO $ doesFileExist (installdir </> "example1" <.> exeExt)
example2Installed <- liftIO $ doesFileExist (installdir </> "example2" <.> exeExt)

assertBool "example1 should have been installed" example1Installed
assertBool "example2 should not have been installed" (not example2Installed)
12 changes: 12 additions & 0 deletions cabal-testsuite/PackageTests/Install/T8614/example.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: example
version: 1.0
build-type: Simple
cabal-version: >= 1.2

executable example1
main-is: example1.hs
build-depends: base

executable example2
main-is: example2.hs
build-depends: base
4 changes: 4 additions & 0 deletions cabal-testsuite/PackageTests/Install/T8614/example1.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Main (main) where

main :: IO ()
main = putStrLn "example1"
4 changes: 4 additions & 0 deletions cabal-testsuite/PackageTests/Install/T8614/example2.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Main (main) where

main :: IO ()
main = putStrLn "example2"
29 changes: 29 additions & 0 deletions changelog.d/12277.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
synopsis: Fix `cabal install <exe>` installing every executable in the package
packages: [cabal-install]
prs: 12277
issues: 8614
---

`cabal install` used to collapse a component target into a whole-package target,
so naming a single executable would build and install *all* of the package's
executables:

```diff
$ cabal install example1 --installdir /tmp/executables
Symlinking 'example1' to '/tmp/executables/example1'
- Symlinking 'example2' to '/tmp/executables/example2'
```

Now the component selector is preserved and only the requested executable is
installed:

```diff
$ cabal install example1 --installdir /tmp/executables
Symlinking 'example1' to '/tmp/executables/example1'
```

This applies to every way of naming a single executable (`example1`,
`exe:example1`, `example:exe:example1`). Whole-package targets such as a bare
package name, `all` or `all:exes` keep their existing behaviour and continue to
install all of the package's executables.
Loading