Skip to content

Commit ee3c313

Browse files
ulysses4everfendor
andauthored
fix cabal install --program-suffix/prefix (fix #10290 and #10476) (#10483)
* fix cabal install --program-suffix/prefix (fix #10290 and #10476) When checking for existing installations, cabal would not account for an affix (suffix or prefix). So, if you had a `hello` binary installed, installing a second one with a non-empty affix (a perfectly legal operation) would fail. The reason seemed to be a typo in 09c04e9, which passed the arguments to the Symlink structure in a wrong order. When failing to install a binary because of an existing one, cabal would report suffix-less existing target even if a suffix was set. * Add regression tests for overwrite policies and porgram-affixes Add regression tests for the `program-prefix` and `program-suffix` flags combined with the overwrite-policy. In short, the overwrite-policy needs to take potential program affixes into account when deciding whether it will need to overwrite a program path during installation. --------- Co-authored-by: Fendor <[email protected]>
1 parent 9e2b2db commit ee3c313

File tree

3 files changed

+228
-2
lines changed

3 files changed

+228
-2
lines changed

cabal-install/src/Distribution/Client/CmdInstall.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,8 +1126,8 @@ symlink
11261126
overwritePolicy
11271127
installDir
11281128
(mkSourceBinDir unit)
1129-
(mkExeName exe)
11301129
(mkFinalExeName exe)
1130+
(mkExeName exe)
11311131

11321132
-- |
11331133
-- -- * When 'InstallCheckOnly', warn if install would fail overwrite policy
@@ -1172,7 +1172,7 @@ installCheckUnitExes
11721172
errorMessage installdir exe = case overwritePolicy of
11731173
NeverOverwrite ->
11741174
"Path '"
1175-
<> (installdir </> prettyShow exe)
1175+
<> (installdir </> mkFinalExeName exe)
11761176
<> "' already exists. "
11771177
<> "Use --overwrite-policy=always to overwrite."
11781178
-- This shouldn't even be possible, but we keep it in case symlinking or
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# cabal install
2+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
3+
Resolving dependencies...
4+
Build profile: -w ghc-<GHCVER> -O1
5+
In order, the following will be built:
6+
- p-1.0 (exe:p) (requires build)
7+
Configuring p-1.0...
8+
Preprocessing executable 'p' for p-1.0...
9+
Building executable 'p' for p-1.0...
10+
Installing executable p in <PATH>
11+
Warning: The directory <ROOT>/overwrite-policy.dist/home/.cabal/store/ghc-<GHCVER>/incoming/new-<RAND><ROOT>/overwrite-policy.dist/home/.cabal/store/ghc-<GHCVER>/<PACKAGE>-<HASH>/bin is not in the system search path.
12+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
13+
# cabal install
14+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
15+
Resolving dependencies...
16+
Error: [Cabal-7149]
17+
Path '<ROOT>/overwrite-policy.dist/usr/bin/p' already exists. Use --overwrite-policy=always to overwrite.
18+
# cabal install
19+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
20+
Resolving dependencies...
21+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
22+
# cabal install
23+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
24+
Resolving dependencies...
25+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
26+
# cabal install
27+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
28+
Resolving dependencies...
29+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p-my-suffix'
30+
# cabal install
31+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
32+
Resolving dependencies...
33+
Error: [Cabal-7149]
34+
Path '<ROOT>/overwrite-policy.dist/usr/bin/p-my-suffix' already exists. Use --overwrite-policy=always to overwrite.
35+
# cabal install
36+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
37+
Resolving dependencies...
38+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p-my-suffix'
39+
# cabal install
40+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
41+
Resolving dependencies...
42+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
43+
# cabal install
44+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
45+
Resolving dependencies...
46+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
47+
# cabal install
48+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
49+
Resolving dependencies...
50+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p'
51+
# cabal install
52+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
53+
Resolving dependencies...
54+
Error: [Cabal-7149]
55+
Path '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p' already exists. Use --overwrite-policy=always to overwrite.
56+
# cabal install
57+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
58+
Resolving dependencies...
59+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p'
60+
# cabal install
61+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
62+
Resolving dependencies...
63+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
64+
# cabal install
65+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
66+
Resolving dependencies...
67+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
68+
# cabal install
69+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
70+
Resolving dependencies...
71+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p-my-suffix'
72+
# cabal install
73+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
74+
Resolving dependencies...
75+
Error: [Cabal-7149]
76+
Path '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p-my-suffix' already exists. Use --overwrite-policy=always to overwrite.
77+
# cabal install
78+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
79+
Resolving dependencies...
80+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p-my-suffix'
81+
# cabal install
82+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
83+
Resolving dependencies...
84+
Symlinking 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
85+
# cabal install
86+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
87+
Resolving dependencies...
88+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
89+
# cabal install
90+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
91+
Resolving dependencies...
92+
Error: [Cabal-7149]
93+
Path '<ROOT>/overwrite-policy.dist/usr/bin/p' already exists. Use --overwrite-policy=always to overwrite.
94+
# cabal install
95+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
96+
Resolving dependencies...
97+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
98+
# cabal install
99+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
100+
Resolving dependencies...
101+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
102+
# cabal install
103+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
104+
Resolving dependencies...
105+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p-my-suffix'
106+
# cabal install
107+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
108+
Resolving dependencies...
109+
Error: [Cabal-7149]
110+
Path '<ROOT>/overwrite-policy.dist/usr/bin/p-my-suffix' already exists. Use --overwrite-policy=always to overwrite.
111+
# cabal install
112+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
113+
Resolving dependencies...
114+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p-my-suffix'
115+
# cabal install
116+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
117+
Resolving dependencies...
118+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
119+
# cabal install
120+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
121+
Resolving dependencies...
122+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
123+
# cabal install
124+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
125+
Resolving dependencies...
126+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p'
127+
# cabal install
128+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
129+
Resolving dependencies...
130+
Error: [Cabal-7149]
131+
Path '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p' already exists. Use --overwrite-policy=always to overwrite.
132+
# cabal install
133+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
134+
Resolving dependencies...
135+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p'
136+
# cabal install
137+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
138+
Resolving dependencies...
139+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
140+
# cabal install
141+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
142+
Resolving dependencies...
143+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
144+
# cabal install
145+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
146+
Resolving dependencies...
147+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p-my-suffix'
148+
# cabal install
149+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
150+
Resolving dependencies...
151+
Error: [Cabal-7149]
152+
Path '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p-my-suffix' already exists. Use --overwrite-policy=always to overwrite.
153+
# cabal install
154+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
155+
Resolving dependencies...
156+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/my-prefix-p-my-suffix'
157+
# cabal install
158+
Wrote tarball sdist to <ROOT>/overwrite-policy.dist/work/./dist/sdist/p-1.0.tar.gz
159+
Resolving dependencies...
160+
Copying 'p' to '<ROOT>/overwrite-policy.dist/usr/bin/p'
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import Test.Cabal.Prelude
2+
import System.FilePath ((</>))
3+
import System.Directory (removeFile)
4+
5+
main = cabalTest $ do
6+
runTestForInstallMethod "symlink"
7+
runTestForInstallMethod "copy"
8+
9+
runTestForInstallMethod :: String -> TestM ()
10+
runTestForInstallMethod method = do
11+
env <- getTestEnv
12+
let installdir = testPrefixDir env </> "bin"
13+
14+
-- install the binary, don't overwrite anything
15+
cabal "install"
16+
["p", "--installdir", installdir, "--install-method", method, "--overwrite-policy", "never"]
17+
-- install the binary, don't overwrite anything
18+
fails $ cabal "install"
19+
["p", "--installdir", installdir, "--install-method", method, "--overwrite-policy", "never"]
20+
-- install the binary again, forcing an overwrite, should succeed.
21+
cabal "install"
22+
["p", "--installdir", installdir, "--install-method", method, "--overwrite-policy", "always"]
23+
-- remove the installed binary.
24+
liftIO $ removeFile (installdir </> "p" <.> exeExt)
25+
26+
testPolicyForAffix installdir method ["--program-suffix", "-my-suffix"]
27+
testPolicyForAffix installdir method ["--program-prefix", "my-prefix-"]
28+
testPolicyForAffix installdir method ["--program-prefix", "my-prefix-", "--program-suffix", "-my-suffix"]
29+
-- remove the installed binaries.
30+
liftIO $ removeFile (installdir </> "p" <.> exeExt)
31+
liftIO $ removeFile (installdir </> "p-my-suffix" <.> exeExt)
32+
liftIO $ removeFile (installdir </> "my-prefix-p" <.> exeExt)
33+
liftIO $ removeFile (installdir </> "my-prefix-p-my-suffix" <.> exeExt)
34+
35+
-- | Run a policy test for a given 'install-method' and program-affix
36+
-- (i.e., '--program-suffix' or '--program-prefix').
37+
--
38+
-- When a program affix is given, the installation should not be affected
39+
-- by installing the binary with no affix and vice-versa.
40+
-- So, installing the program without any affix is not affected by installations with
41+
-- some program affix.
42+
testPolicyForAffix :: FilePath -> String -> [String] -> TestM ()
43+
testPolicyForAffix installdir method affixArgs = do
44+
-- install the binary again, forcing an overwrite, must succeed.
45+
-- The rest of this test assumes the binary has been installed before.
46+
cabal "install"
47+
["p", "--installdir", installdir, "--install-method", method, "--overwrite-policy", "always"]
48+
49+
-- Install the binary with some program affix, don't need overwrite anything
50+
cabal "install"
51+
(["p", "--installdir", installdir, "--install-method", method, "--overwrite-policy", "never"] ++ affixArgs)
52+
-- Once the binary is installed, we can't overwrite it unless we are told so.
53+
fails $ cabal "install"
54+
(["p", "--installdir", installdir, "--install-method", method, "--overwrite-policy", "never"] ++ affixArgs)
55+
-- Successfully overwrite the binary if told so.
56+
cabal "install"
57+
(["p", "--installdir", installdir, "--install-method", method, "--overwrite-policy", "always"] ++ affixArgs)
58+
59+
-- remove the installed binary.
60+
liftIO $ removeFile (installdir </> "p" <.> exeExt)
61+
-- Make sure we can still install the original program with no program affix without overwriting,
62+
-- even though, the program is already installed with some affix.
63+
cabal "install"
64+
["p", "--installdir", installdir, "--install-method", method, "--overwrite-policy", "never"]
65+
66+
exeExt = if isWindows then "exe" else ""

0 commit comments

Comments
 (0)