1
+ {-# LANGUAGE CPP #-}
1
2
-----------------------------------------------------------------------------
2
3
-- |
3
4
-- Module : Distribution.Client.SetupWrapper
@@ -97,6 +98,16 @@ import Data.Maybe ( fromMaybe, isJust )
97
98
import Data.Monoid ( mempty )
98
99
import Data.Char ( isSpace )
99
100
101
+ #ifdef mingw32_HOST_OS
102
+ import Distribution.Simple.Utils
103
+ ( withTempDirectory )
104
+
105
+ import Control.Exception ( bracket )
106
+ import System.FilePath ( equalFilePath , takeDirectory )
107
+ import System.Directory ( doesDirectoryExist )
108
+ import qualified System.Win32 as Win32
109
+ #endif
110
+
100
111
data SetupScriptOptions = SetupScriptOptions {
101
112
useCabalVersion :: VersionRange ,
102
113
useCompiler :: Maybe Compiler ,
@@ -109,6 +120,12 @@ data SetupScriptOptions = SetupScriptOptions {
109
120
useWorkingDir :: Maybe FilePath ,
110
121
forceExternalSetupMethod :: Bool ,
111
122
123
+ -- On Windows, running './dist/setup/setup clean' doesn't work because the
124
+ -- setup script will try to delete itself. So we have to move the setup exe
125
+ -- out of the way first and then delete it manually. This applies only to
126
+ -- the external setup method.
127
+ useWin32CleanHack :: Bool ,
128
+
112
129
-- Used only when calling setupWrapper from parallel code to serialise
113
130
-- access to the setup cache; should be Nothing otherwise.
114
131
--
@@ -135,6 +152,7 @@ defaultSetupScriptOptions = SetupScriptOptions {
135
152
useDistPref = defaultDistPref,
136
153
useLoggingHandle = Nothing ,
137
154
useWorkingDir = Nothing ,
155
+ useWin32CleanHack = False ,
138
156
forceExternalSetupMethod = False ,
139
157
setupCacheLock = Nothing
140
158
}
@@ -491,12 +509,46 @@ externalSetupMethod verbosity options pkg bt mkargs = do
491
509
-- working directory.
492
510
path' <- tryCanonicalizePath path
493
511
494
- searchpath <- programSearchPathAsPATHVar
495
- (getProgramSearchPath (useProgramConfig options'))
496
- env <- getEffectiveEnvironment [(" PATH" , Just searchpath)]
512
+ #if mingw32_HOST_OS
513
+ setupProgFile' <- tryCanonicalizePath setupProgFile
514
+ let win32CleanHackNeeded = (useWin32CleanHack options')
515
+ -- Skip when a cached setup script is used.
516
+ && setupProgFile' `equalFilePath` path'
517
+ if win32CleanHackNeeded then doWin32CleanHack path' else doInvoke path'
518
+ #else
519
+ doInvoke path'
520
+ #endif
497
521
498
- process <- runProcess path' args
499
- (useWorkingDir options') env
500
- Nothing (useLoggingHandle options') (useLoggingHandle options')
501
- exitCode <- waitForProcess process
502
- unless (exitCode == ExitSuccess ) $ exitWith exitCode
522
+ where
523
+ doInvoke path' = do
524
+ searchpath <- programSearchPathAsPATHVar
525
+ (getProgramSearchPath (useProgramConfig options'))
526
+ env <- getEffectiveEnvironment [(" PATH" , Just searchpath)]
527
+
528
+ process <- runProcess path' args
529
+ (useWorkingDir options') env Nothing
530
+ (useLoggingHandle options') (useLoggingHandle options')
531
+ exitCode <- waitForProcess process
532
+ unless (exitCode == ExitSuccess ) $ exitWith exitCode
533
+
534
+ #if mingw32_HOST_OS
535
+ doWin32CleanHack path' = do
536
+ info verbosity $ " Using the Win32 clean hack."
537
+ -- Recursively removes the temp dir on exit.
538
+ withTempDirectory verbosity workingDir " cabal-tmp" $ \ tmpDir ->
539
+ bracket (moveOutOfTheWay tmpDir path')
540
+ (maybeRestore path')
541
+ doInvoke
542
+
543
+ moveOutOfTheWay tmpDir path' = do
544
+ let newPath = tmpDir </> " setup" <.> exeExtension
545
+ Win32. moveFile path' newPath
546
+ return newPath
547
+
548
+ maybeRestore oldPath path' = do
549
+ let oldPathDir = takeDirectory oldPath
550
+ oldPathDirExists <- doesDirectoryExist oldPathDir
551
+ -- 'setup clean' didn't complete, 'dist/setup' still exists.
552
+ when oldPathDirExists $
553
+ Win32. moveFile path' oldPath
554
+ #endif
0 commit comments