Skip to content

Commit 03b02fb

Browse files
committed
Allow using cabal program itself as the external setup method
This fixes issues when the version of Cabal that cabal-install was built against differs from the one registered in the local package DB. Normally we compile an external setup against the local Cabal library, which could lead to failures or inconsistent results compared to using the internal method. This fixes #2438 and fixes #1938.
1 parent 776e9e2 commit 03b02fb

File tree

3 files changed

+108
-8
lines changed

3 files changed

+108
-8
lines changed

cabal-install/Distribution/Client/Setup.hs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ module Distribution.Client.Setup
3535
, initCommand, IT.InitFlags(..)
3636
, sdistCommand, SDistFlags(..), SDistExFlags(..), ArchiveFormat(..)
3737
, win32SelfUpgradeCommand, Win32SelfUpgradeFlags(..)
38+
, actAsSetupCommand, ActAsSetupFlags(..)
3839
, sandboxCommand, defaultSandboxLocation, SandboxFlags(..)
3940
, execCommand, ExecFlags(..)
4041
, userConfigCommand, UserConfigFlags(..)
@@ -79,7 +80,7 @@ import Distribution.Version
7980
import Distribution.Package
8081
( PackageIdentifier, packageName, packageVersion, Dependency(..) )
8182
import Distribution.PackageDescription
82-
( RepoKind(..) )
83+
( BuildType(..), RepoKind(..) )
8384
import Distribution.Text
8485
( Text(..), display )
8586
import Distribution.ReadE
@@ -1813,6 +1814,47 @@ instance Monoid Win32SelfUpgradeFlags where
18131814
}
18141815
where combine field = field a `mappend` field b
18151816

1817+
-- ------------------------------------------------------------
1818+
-- * ActAsSetup flags
1819+
-- ------------------------------------------------------------
1820+
1821+
data ActAsSetupFlags = ActAsSetupFlags {
1822+
actAsSetupBuildType :: Flag BuildType
1823+
}
1824+
1825+
defaultActAsSetupFlags :: ActAsSetupFlags
1826+
defaultActAsSetupFlags = ActAsSetupFlags {
1827+
actAsSetupBuildType = toFlag Simple
1828+
}
1829+
1830+
actAsSetupCommand :: CommandUI ActAsSetupFlags
1831+
actAsSetupCommand = CommandUI {
1832+
commandName = "act-as-setup",
1833+
commandSynopsis = "Run as-if this was a Setup.hs",
1834+
commandDescription = Nothing,
1835+
commandNotes = Nothing,
1836+
commandUsage = \pname ->
1837+
"Usage: " ++ pname ++ " act-as-setup\n",
1838+
commandDefaultFlags = defaultActAsSetupFlags,
1839+
commandOptions = \_ ->
1840+
[option "" ["build-type"]
1841+
"Use the given build type."
1842+
actAsSetupBuildType (\v flags -> flags { actAsSetupBuildType = v })
1843+
(reqArg "BUILD-TYPE" (readP_to_E ("Cannot parse build type: "++)
1844+
(fmap toFlag parse))
1845+
(map display . flagToList))
1846+
]
1847+
}
1848+
1849+
instance Monoid ActAsSetupFlags where
1850+
mempty = ActAsSetupFlags {
1851+
actAsSetupBuildType = mempty
1852+
}
1853+
mappend a b = ActAsSetupFlags {
1854+
actAsSetupBuildType = combine actAsSetupBuildType
1855+
}
1856+
where combine field = field a `mappend` field b
1857+
18161858
-- ------------------------------------------------------------
18171859
-- * Sandbox-related flags
18181860
-- ------------------------------------------------------------

cabal-install/Distribution/Client/SetupWrapper.hs

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ import Control.Monad ( when, unless )
105105
import Data.List ( foldl1' )
106106
import Data.Maybe ( fromMaybe, isJust )
107107
import Data.Char ( isSpace )
108+
import Distribution.Client.Compat.ExecutablePath ( getExecutablePath )
108109

109110
#ifdef mingw32_HOST_OS
110111
import Distribution.Simple.Utils
@@ -222,12 +223,22 @@ setupWrapper verbosity options mpkg cmd flags extraArgs = do
222223
--
223224
determineSetupMethod :: SetupScriptOptions -> BuildType -> SetupMethod
224225
determineSetupMethod options buildType'
225-
| forceExternalSetupMethod options = externalSetupMethod
226+
-- This order is picked so that it's stable. The build type and
227+
-- required cabal version are external info, coming from .cabal
228+
-- files and the command line. Those do switch between the
229+
-- external and self & internal methods, but that info itself can
230+
-- be considered stable. The logging and force-external conditions
231+
-- are internally generated choices but now these only switch
232+
-- between the self and internal setup methods, which are
233+
-- consistent with each other.
234+
| buildType' == Custom = externalSetupMethod
235+
| not (cabalVersion `withinRange`
236+
useCabalVersion options) = externalSetupMethod
226237
| isJust (useLoggingHandle options)
227-
|| buildType' == Custom = externalSetupMethod
228-
| cabalVersion `withinRange`
229-
useCabalVersion options = internalSetupMethod
230-
| otherwise = externalSetupMethod
238+
-- Forcing is done to use an external process e.g. due to parallel
239+
-- build concerns.
240+
|| forceExternalSetupMethod options = selfExecSetupMethod
241+
| otherwise = internalSetupMethod
231242

232243
type SetupMethod = Verbosity
233244
-> SetupScriptOptions
@@ -255,6 +266,34 @@ buildTypeAction Make = Make.defaultMainArgs
255266
buildTypeAction Custom = error "buildTypeAction Custom"
256267
buildTypeAction (UnknownBuildType _) = error "buildTypeAction UnknownBuildType"
257268

269+
-- ------------------------------------------------------------
270+
-- * Self-Exec SetupMethod
271+
-- ------------------------------------------------------------
272+
273+
selfExecSetupMethod :: SetupMethod
274+
selfExecSetupMethod verbosity options _pkg bt mkargs = do
275+
let args = ["act-as-setup",
276+
"--build-type=" ++ display bt,
277+
"--"] ++ mkargs cabalVersion
278+
debug verbosity $ "Using self-exec internal setup method with build-type "
279+
++ show bt ++ " and args:\n " ++ show args
280+
path <- getExecutablePath
281+
info verbosity $ unwords (path : args)
282+
case useLoggingHandle options of
283+
Nothing -> return ()
284+
Just logHandle -> info verbosity $ "Redirecting build log to "
285+
++ show logHandle
286+
287+
searchpath <- programSearchPathAsPATHVar
288+
(getProgramSearchPath (useProgramConfig options))
289+
env <- getEffectiveEnvironment [("PATH", Just searchpath)]
290+
291+
process <- runProcess path args
292+
(useWorkingDir options) env Nothing
293+
(useLoggingHandle options) (useLoggingHandle options)
294+
exitCode <- waitForProcess process
295+
unless (exitCode == ExitSuccess) $ exitWith exitCode
296+
258297
-- ------------------------------------------------------------
259298
-- * External SetupMethod
260299
-- ------------------------------------------------------------

cabal-install/Main.hs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import Distribution.Client.Setup
3737
, InitFlags(initVerbosity), initCommand
3838
, SDistFlags(..), SDistExFlags(..), sdistCommand
3939
, Win32SelfUpgradeFlags(..), win32SelfUpgradeCommand
40+
, ActAsSetupFlags(..), actAsSetupCommand
4041
, SandboxFlags(..), sandboxCommand
4142
, ExecFlags(..), execCommand
4243
, UserConfigFlags(..), userConfigCommand
@@ -112,12 +113,14 @@ import Distribution.Client.Utils (determineNumJobs
112113
,existsAndIsMoreRecentThan)
113114

114115
import Distribution.PackageDescription
115-
( Executable(..), benchmarkName, benchmarkBuildInfo, testName
116-
, testBuildInfo, buildable )
116+
( BuildType(..), Executable(..), benchmarkName, benchmarkBuildInfo
117+
, testName, testBuildInfo, buildable )
117118
import Distribution.PackageDescription.Parse
118119
( readPackageDescription )
119120
import Distribution.PackageDescription.PrettyPrint
120121
( writeGenericPackageDescription )
122+
import qualified Distribution.Simple as Simple
123+
import qualified Distribution.Make as Make
121124
import Distribution.Simple.Build
122125
( startInterpreter )
123126
import Distribution.Simple.Command
@@ -262,6 +265,8 @@ mainWorker args = topHandler $
262265
upgradeCommand `commandAddAction` upgradeAction
263266
,hiddenCommand $
264267
win32SelfUpgradeCommand`commandAddAction` win32SelfUpgradeAction
268+
,hiddenCommand $
269+
actAsSetupCommand`commandAddAction` actAsSetupAction
265270
]
266271

267272
wrapperAction :: Monoid flags
@@ -1155,3 +1160,17 @@ win32SelfUpgradeAction selfUpgradeFlags (pid:path:_extraArgs) _globalFlags = do
11551160
let verbosity = fromFlag (win32SelfUpgradeVerbosity selfUpgradeFlags)
11561161
Win32SelfUpgrade.deleteOldExeFile verbosity (read pid) path
11571162
win32SelfUpgradeAction _ _ _ = return ()
1163+
1164+
-- | Used as an entry point when cabal-install needs to invoke itself
1165+
-- as a setup script. This can happen e.g. when doing parallel builds.
1166+
--
1167+
actAsSetupAction :: ActAsSetupFlags -> [String] -> GlobalFlags -> IO ()
1168+
actAsSetupAction actAsSetupFlags args _globalFlags =
1169+
let bt = fromFlag (actAsSetupBuildType actAsSetupFlags)
1170+
in case bt of
1171+
Simple -> Simple.defaultMainArgs args
1172+
Configure -> Simple.defaultMainWithHooksArgs
1173+
Simple.autoconfUserHooks args
1174+
Make -> Make.defaultMainArgs args
1175+
Custom -> error "actAsSetupAction Custom"
1176+
(UnknownBuildType _) -> error "actAsSetupAction UnknownBuildType"

0 commit comments

Comments
 (0)