@@ -16,47 +16,9 @@ module Distribution.Client.InstallSymlink (
16
16
OverwritePolicy (.. ),
17
17
symlinkBinaries ,
18
18
symlinkBinary ,
19
+ trySymlink ,
19
20
) where
20
21
21
- #ifdef mingw32_HOST_OS
22
-
23
- import Distribution.Compat.Binary
24
- ( Binary )
25
- import Distribution.Utils.Structured
26
- ( Structured )
27
-
28
- import Distribution.Package (PackageIdentifier )
29
- import Distribution.Types.UnqualComponentName
30
- import Distribution.Client.InstallPlan (InstallPlan )
31
- import Distribution.Client.Types (BuildOutcomes )
32
- import Distribution.Client.Setup (InstallFlags )
33
- import Distribution.Simple.Setup (ConfigFlags )
34
- import Distribution.Simple.Compiler
35
- import Distribution.System
36
- import GHC.Generics (Generic )
37
-
38
- data OverwritePolicy = NeverOverwrite | AlwaysOverwrite
39
- deriving (Show , Eq , Generic , Bounded , Enum )
40
-
41
- instance Binary OverwritePolicy
42
- instance Structured OverwritePolicy
43
-
44
- symlinkBinaries :: Platform -> Compiler
45
- -> OverwritePolicy
46
- -> ConfigFlags
47
- -> InstallFlags
48
- -> InstallPlan
49
- -> BuildOutcomes
50
- -> IO [(PackageIdentifier , UnqualComponentName , FilePath )]
51
- symlinkBinaries _ _ _ _ _ _ _ = return []
52
-
53
- symlinkBinary :: OverwritePolicy
54
- -> FilePath -> FilePath -> FilePath -> String
55
- -> IO Bool
56
- symlinkBinary _ _ _ _ _ = fail " Symlinking feature not available on Windows"
57
-
58
- #else
59
-
60
22
import Distribution.Compat.Binary
61
23
( Binary )
62
24
import Distribution.Utils.Structured
@@ -91,12 +53,11 @@ import Distribution.System
91
53
( Platform )
92
54
import Distribution.Deprecated.Text
93
55
( display )
56
+ import Distribution.Verbosity ( Verbosity )
57
+ import Distribution.Simple.Utils ( info , withTempDirectory )
94
58
95
- import System.Posix.Files
96
- ( getSymbolicLinkStatus , isSymbolicLink , createSymbolicLink
97
- , removeLink )
98
59
import System.Directory
99
- ( canonicalizePath )
60
+ ( canonicalizePath , getTemporaryDirectory , removeFile )
100
61
import System.FilePath
101
62
( (</>) , splitPath , joinPath , isAbsolute )
102
63
@@ -111,6 +72,11 @@ import Data.Maybe
111
72
import GHC.Generics
112
73
( Generic )
113
74
75
+ import Distribution.Client.Compat.Directory ( createFileLink , getSymbolicLinkTarget , pathIsSymbolicLink )
76
+
77
+ import qualified Data.ByteString as BS
78
+ import qualified Data.ByteString.Char8 as BS8
79
+
114
80
data OverwritePolicy = NeverOverwrite | AlwaysOverwrite
115
81
deriving (Show , Eq , Generic , Bounded , Enum )
116
82
@@ -246,9 +212,8 @@ symlinkBinary overwritePolicy publicBindir privateBindir publicName privateName
246
212
AlwaysOverwrite -> rmLink >> mkLink >> return True
247
213
where
248
214
relativeBindir = makeRelative publicBindir privateBindir
249
- mkLink = createSymbolicLink (relativeBindir </> privateName)
250
- (publicBindir </> publicName)
251
- rmLink = removeLink (publicBindir </> publicName)
215
+ mkLink = createFileLink (relativeBindir </> privateName) (publicBindir </> publicName)
216
+ rmLink = removeFile (publicBindir </> publicName)
252
217
253
218
-- | Check a file path of a symlink that we would like to create to see if it
254
219
-- is OK. For it to be OK to overwrite it must either not already exist yet or
@@ -260,11 +225,11 @@ targetOkToOverwrite :: FilePath -- ^ The file path of the symlink to the private
260
225
-- Use 'canonicalizePath' to make this.
261
226
-> IO SymlinkStatus
262
227
targetOkToOverwrite symlink target = handleNotExist $ do
263
- status <- getSymbolicLinkStatus symlink
264
- if not (isSymbolicLink status)
228
+ isLink <- pathIsSymbolicLink symlink
229
+ if not isLink
265
230
then return NotOurFile
266
- else do target' <- canonicalizePath symlink
267
- -- This relies on canonicalizePath handling symlinks
231
+ else do target' <- canonicalizePath =<< getSymbolicLinkTarget symlink
232
+ -- This partially relies on canonicalizePath handling symlinks
268
233
if target == target'
269
234
then return OkToOverwrite
270
235
else return NotOurFile
@@ -296,4 +261,27 @@ makeRelative a b = assert (isAbsolute a && isAbsolute b) $
296
261
in joinPath $ [ " .." | _ <- drop commonLen as ]
297
262
++ drop commonLen bs
298
263
299
- #endif
264
+ -- | Try to make a symlink in a temporary directory.
265
+ --
266
+ -- If this works, we can try to symlink: even on Windows.
267
+ --
268
+ trySymlink :: Verbosity -> IO Bool
269
+ trySymlink verbosity = do
270
+ tmp <- getTemporaryDirectory
271
+ withTempDirectory verbosity tmp " cabal-symlink-test" $ \ tmpDirPath -> do
272
+ let from = tmpDirPath </> " file.txt"
273
+ let to = tmpDirPath </> " file2.txt"
274
+
275
+ -- create a file
276
+ BS. writeFile from (BS8. pack " TEST" )
277
+
278
+ -- create a symbolic link
279
+ let create :: IO Bool
280
+ create = do
281
+ createFileLink from to
282
+ info verbosity $ " Symlinking seems to work"
283
+ return True
284
+
285
+ create `catchIO` \ exc -> do
286
+ info verbosity $ " Symlinking doesn't seem to be working: " ++ show exc
287
+ return False
0 commit comments