From 0f12d92d7ad9e215e07cb20fbdc074dc53c38889 Mon Sep 17 00:00:00 2001
From: Pierre Le Marre <dev@wismill.eu>
Date: Sat, 25 May 2024 15:46:55 +0200
Subject: [PATCH] Fix --program-{prefix,suffix} resulting in invalid
 installation

Currently the options `--program-{prefix,suffix}` for cabal install
affects the name of the file in the install directory *and* the
executable name in the store. The installation fails:

- If using `--install-method=symlink`, the *target* of the symlink is
  not affected by the affix options and it results in an invalid symlink.
- If using `--install-method=copy`, the copy fails because the source
  is not found.

Another issue is that it affects the computation of the hash of the
build directory in the store, resulting in needless rebuild when using
successively different affix options.

Fixed by making the name of the executable in the store canonical, i.e.
always ignoring the program affix options.

Added a test for all the combinations of `--install-method` and program
affixes options.

(cherry picked from commit 859347426ec5a4b4577d8a4c9fa38e877167d525)

# Conflicts:
#	cabal-install/src/Distribution/Client/CmdInstall.hs
---
 .../src/Distribution/Client/CmdInstall.hs     | 17 ++++++++++++
 .../Install/ProgramAffixes/Main.hs            |  1 +
 .../Install/ProgramAffixes/cabal.project      |  1 +
 .../Install/ProgramAffixes/cabal.test.hs      | 27 +++++++++++++++++++
 .../Install/ProgramAffixes/p.cabal            |  8 ++++++
 changelog.d/issue-9919                        |  4 +++
 6 files changed, 58 insertions(+)
 create mode 100644 cabal-testsuite/PackageTests/Install/ProgramAffixes/Main.hs
 create mode 100644 cabal-testsuite/PackageTests/Install/ProgramAffixes/cabal.project
 create mode 100644 cabal-testsuite/PackageTests/Install/ProgramAffixes/cabal.test.hs
 create mode 100644 cabal-testsuite/PackageTests/Install/ProgramAffixes/p.cabal
 create mode 100644 changelog.d/issue-9919

diff --git a/cabal-install/src/Distribution/Client/CmdInstall.hs b/cabal-install/src/Distribution/Client/CmdInstall.hs
index a70d3bcedc..a4ad8d1d6e 100644
--- a/cabal-install/src/Distribution/Client/CmdInstall.hs
+++ b/cabal-install/src/Distribution/Client/CmdInstall.hs
@@ -538,8 +538,13 @@ installAction flags@NixStyleFlags{extraFlags, configFlags, installFlags, project
         -- BuildOutcomes because we also need the component names
           traverseInstall (installCheckUnitExes InstallCheckInstall) installCfg
   where
+<<<<<<< HEAD
     configFlags' = disableTestsBenchsByDefault configFlags
     verbosity = fromFlagOrDefault normal (configVerbosity configFlags')
+=======
+    configFlags' = disableTestsBenchsByDefault . ignoreProgramAffixes $ configFlags
+    verbosity = fromFlagOrDefault normal (setupVerbosity $ configCommonFlags configFlags')
+>>>>>>> 859347426 (Fix --program-{prefix,suffix} resulting in invalid installation)
     ignoreProject = flagIgnoreProject projectFlags
     cliConfig =
       commandLineFlagsToProjectConfig
@@ -1099,6 +1104,18 @@ disableTestsBenchsByDefault configFlags =
     , configBenchmarks = Flag False <> configBenchmarks configFlags
     }
 
+-- | Disables program prefix and suffix, in order to get the /canonical/
+-- executable name in the store and thus:
+--
+-- * avoid making the package hash depend on these options and needless rebuild;
+-- * provide the correct executable path to the install methods (copy, symlink).
+ignoreProgramAffixes :: ConfigFlags -> ConfigFlags
+ignoreProgramAffixes configFlags =
+  configFlags
+    { configProgPrefix = NoFlag
+    , configProgSuffix = NoFlag
+    }
+
 -- | Prepares a record containing the information needed to either symlink or
 -- copy an executable.
 symlink :: OverwritePolicy -> InstallExe -> UnitId -> UnqualComponentName -> Symlink
diff --git a/cabal-testsuite/PackageTests/Install/ProgramAffixes/Main.hs b/cabal-testsuite/PackageTests/Install/ProgramAffixes/Main.hs
new file mode 100644
index 0000000000..76a9bdb5d4
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Install/ProgramAffixes/Main.hs
@@ -0,0 +1 @@
+main = pure ()
diff --git a/cabal-testsuite/PackageTests/Install/ProgramAffixes/cabal.project b/cabal-testsuite/PackageTests/Install/ProgramAffixes/cabal.project
new file mode 100644
index 0000000000..e6fdbadb43
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Install/ProgramAffixes/cabal.project
@@ -0,0 +1 @@
+packages: .
diff --git a/cabal-testsuite/PackageTests/Install/ProgramAffixes/cabal.test.hs b/cabal-testsuite/PackageTests/Install/ProgramAffixes/cabal.test.hs
new file mode 100644
index 0000000000..c02eda531f
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Install/ProgramAffixes/cabal.test.hs
@@ -0,0 +1,27 @@
+import Test.Cabal.Prelude
+import Data.Foldable (traverse_)
+
+-- Test that program affixes options result in successful installation:
+-- • Valid symlinks (--install-method=symlink)
+-- • Valid copy of executables (--install-method=copy)
+main = cabalTest $ do
+  env <- getTestEnv
+  recordMode DoNotRecord $ do
+    let installdir = testPrefixDir env </> "bin"
+        commonOpts = ["p", "--installdir", installdir, "--overwrite-policy=always"]
+        testAllAffixes installMethod = do
+          let testAffixes' = testAffixes
+                (commonOpts ++ ["--install-method", installMethod])
+          testAffixes' Nothing Nothing
+          testAffixes' (Just "a-") Nothing
+          testAffixes' Nothing (Just "-z")
+          testAffixes' (Just "a-") (Just "-z")
+    traverse_ testAllAffixes ["symlink", "copy"]
+  where
+    mkAffixOption option = maybe [] (\a -> ["--program-" ++ option, a])
+    mkProgramName p s = maybe [] id p ++ "p" ++ maybe [] id s
+    testAffixes commonOpts prefix suffix = do
+      cabal "install" (  commonOpts
+                      ++ mkAffixOption "prefix" prefix
+                      ++ mkAffixOption "suffix" suffix)
+      runInstalledExe (mkProgramName prefix suffix) []
diff --git a/cabal-testsuite/PackageTests/Install/ProgramAffixes/p.cabal b/cabal-testsuite/PackageTests/Install/ProgramAffixes/p.cabal
new file mode 100644
index 0000000000..30428ef4ac
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Install/ProgramAffixes/p.cabal
@@ -0,0 +1,8 @@
+name: p
+version: 1.0
+build-type: Simple
+cabal-version: >= 1.2
+
+executable p
+  main-is: Main.hs
+  build-depends: base
diff --git a/changelog.d/issue-9919 b/changelog.d/issue-9919
new file mode 100644
index 0000000000..a4fe32bbde
--- /dev/null
+++ b/changelog.d/issue-9919
@@ -0,0 +1,4 @@
+synopsis: Fix --program-suffix resulting in invalid installation
+packages: cabal-install
+issues: #8823 #9919
+prs: #10056
-- 
GitLab