@@ -11,6 +11,7 @@ module Distribution.Client.Sandbox (
11
11
sandboxInit ,
12
12
sandboxDelete ,
13
13
sandboxAddSource ,
14
+ sandboxAddSourceSnapshot ,
14
15
sandboxDeleteSource ,
15
16
sandboxListSources ,
16
17
sandboxHcPkg ,
@@ -59,36 +60,54 @@ import Distribution.Client.Targets ( UserTarget(..)
59
60
, readUserTargets
60
61
, resolveUserTargets )
61
62
import Distribution.Client.Types ( SourcePackageDb (.. ) )
62
- import Distribution.Client.Utils ( tryCanonicalizePath )
63
+ import Distribution.Client.Utils ( inDir , tryCanonicalizePath )
64
+ import Distribution.PackageDescription.Configuration
65
+ ( flattenPackageDescription )
66
+ import Distribution.PackageDescription.Parse ( readPackageDescription )
63
67
import Distribution.Simple.Compiler ( Compiler (.. ), PackageDB (.. )
64
68
, PackageDBStack )
65
69
import Distribution.Simple.Configure ( configCompilerAux
66
70
, interpretPackageDbFlags )
71
+ import Distribution.Simple.PreProcess ( knownSuffixHandlers )
67
72
import Distribution.Simple.Program ( ProgramConfiguration )
68
73
import Distribution.Simple.Setup ( Flag (.. )
69
74
, fromFlag , fromFlagOrDefault )
75
+ import Distribution.Simple.SrcDist ( prepareTree )
70
76
import Distribution.Simple.Utils ( die , debug , notice , info
71
- , debugNoWrap
77
+ , debugNoWrap , defaultPackageDesc
72
78
, intercalate
73
79
, createDirectoryIfMissingVerbose )
80
+ import Distribution.Package ( Package (.. ) )
74
81
import Distribution.System ( Platform )
82
+ import Distribution.Text ( display )
75
83
import Distribution.Verbosity ( Verbosity , lessVerbose )
76
84
import Distribution.Compat.Env ( lookupEnv , setEnv )
77
85
import qualified Distribution.Client.Sandbox.Index as Index
78
86
import qualified Distribution.Simple.Register as Register
79
87
import Control.Exception ( assert , bracket_ )
80
- import Control.Monad ( unless , when )
88
+ import Control.Monad ( forM , unless , when )
81
89
import Data.IORef ( newIORef , writeIORef , readIORef )
82
90
import Data.List ( (\\) , delete )
83
91
import Data.Monoid ( mempty , mappend )
84
- import System.Directory ( doesDirectoryExist
92
+ import System.Directory ( createDirectory
93
+ , doesDirectoryExist
85
94
, getCurrentDirectory
86
95
, removeDirectoryRecursive
87
- , removeFile )
96
+ , removeFile
97
+ , renameDirectory )
88
98
import System.FilePath ( (</>) , getSearchPath
89
99
, searchPathSeparator )
90
100
91
101
102
+ --
103
+ -- * Constants
104
+ --
105
+
106
+ -- | The name of the sandbox subdirectory where we keep snapshots of add-source
107
+ -- dependencies.
108
+ snapshotDirectoryName :: FilePath
109
+ snapshotDirectoryName = " snapshots"
110
+
92
111
--
93
112
-- * Basic sandbox functions.
94
113
--
@@ -220,12 +239,9 @@ sandboxDelete verbosity _sandboxFlags globalFlags = do
220
239
notice verbosity $ " Deleting the sandbox located at " ++ sandboxDir
221
240
removeDirectoryRecursive sandboxDir
222
241
223
- -- | Entry point for the 'cabal sandbox add-source' command.
224
- sandboxAddSource :: Verbosity -> [FilePath ] -> SandboxFlags -> GlobalFlags
225
- -> IO ()
226
- sandboxAddSource verbosity buildTreeRefs _sandboxFlags globalFlags = do
227
- (sandboxDir, pkgEnv) <- tryLoadSandboxConfig verbosity
228
- (globalConfigFile globalFlags)
242
+ -- Common implementation of 'sandboxAddSource' and 'sandboxAddSourceSnapshot'.
243
+ doAddSource :: Verbosity -> [FilePath ] -> FilePath -> PackageEnvironment -> IO ()
244
+ doAddSource verbosity buildTreeRefs sandboxDir pkgEnv = do
229
245
let savedConfig = pkgEnvSavedConfig pkgEnv
230
246
indexFile <- tryGetIndexFilePath savedConfig
231
247
@@ -241,6 +257,63 @@ sandboxAddSource verbosity buildTreeRefs _sandboxFlags globalFlags = do
241
257
Index. addBuildTreeRefs verbosity indexFile buildTreeRefs'
242
258
return buildTreeRefs'
243
259
260
+ -- | Entry point for the 'cabal sandbox add-source' command.
261
+ sandboxAddSource :: Verbosity -> [FilePath ] -> SandboxFlags -> GlobalFlags
262
+ -> IO ()
263
+ sandboxAddSource verbosity buildTreeRefs sandboxFlags globalFlags = do
264
+ (sandboxDir, pkgEnv) <- tryLoadSandboxConfig verbosity
265
+ (globalConfigFile globalFlags)
266
+
267
+ if fromFlagOrDefault False (sandboxSnapshot sandboxFlags)
268
+ then sandboxAddSourceSnapshot verbosity buildTreeRefs sandboxDir pkgEnv
269
+ else doAddSource verbosity buildTreeRefs sandboxDir pkgEnv
270
+
271
+ -- | Entry point for the 'cabal sandbox add-source --snapshot' command.
272
+ sandboxAddSourceSnapshot :: Verbosity -> [FilePath ] -> FilePath
273
+ -> PackageEnvironment
274
+ -> IO ()
275
+ sandboxAddSourceSnapshot verbosity buildTreeRefs sandboxDir pkgEnv = do
276
+ let snapshotDir = sandboxDir </> snapshotDirectoryName
277
+
278
+ -- Use 'D.S.SrcDist.prepareTree' to copy each package's files to our private
279
+ -- location.
280
+ createDirectoryIfMissingVerbose verbosity True snapshotDir
281
+
282
+ -- Collect the package descriptions first, so that if some path does not refer
283
+ -- to a cabal package, we fail immediately.
284
+ pkgs <- forM buildTreeRefs $ \ buildTreeRef ->
285
+ inDir (Just buildTreeRef) $
286
+ return . flattenPackageDescription
287
+ =<< readPackageDescription verbosity
288
+ =<< defaultPackageDesc verbosity
289
+
290
+ -- Copy the package sources to "snapshots/$PKGNAME-$VERSION-tmp". If
291
+ -- 'prepareTree' throws an error at any point, the old snapshots will still be
292
+ -- in consistent state.
293
+ tmpDirs <- forM (zip buildTreeRefs pkgs) $ \ (buildTreeRef, pkg) ->
294
+ inDir (Just buildTreeRef) $ do
295
+ let targetDir = snapshotDir </> (display . packageId $ pkg)
296
+ targetTmpDir = targetDir ++ " -tmp"
297
+ dirExists <- doesDirectoryExist targetTmpDir
298
+ when dirExists $
299
+ removeDirectoryRecursive targetDir
300
+ createDirectory targetTmpDir
301
+ prepareTree verbosity pkg Nothing buildTreeRef targetTmpDir
302
+ knownSuffixHandlers
303
+ return (targetTmpDir, targetDir)
304
+
305
+ -- Now rename the "snapshots/$PKGNAME-$VERSION-tmp" dirs to
306
+ -- "snapshots/$PKGNAME-$VERSION".
307
+ snapshots <- forM tmpDirs $ \ (targetTmpDir, targetDir) -> do
308
+ dirExists <- doesDirectoryExist targetDir
309
+ when dirExists $
310
+ removeDirectoryRecursive targetDir
311
+ renameDirectory targetTmpDir targetDir
312
+ return targetDir
313
+
314
+ -- Once the packages are copied, just 'add-source' them as usual.
315
+ doAddSource verbosity snapshots sandboxDir pkgEnv
316
+
244
317
-- | Entry point for the 'cabal sandbox delete-source' command.
245
318
sandboxDeleteSource :: Verbosity -> [FilePath ] -> SandboxFlags -> GlobalFlags
246
319
-> IO ()
0 commit comments