Skip to content

Commit 74d7a8e

Browse files
committed
Merge pull request #1296 from 23Skidoo/add-source-snapshot
Implement 'sandbox add-source --snapshot'.
2 parents aae9ba5 + 20fe448 commit 74d7a8e

File tree

3 files changed

+103
-15
lines changed

3 files changed

+103
-15
lines changed

cabal-install/Distribution/Client/Sandbox.hs

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Distribution.Client.Sandbox (
1111
sandboxInit,
1212
sandboxDelete,
1313
sandboxAddSource,
14+
sandboxAddSourceSnapshot,
1415
sandboxDeleteSource,
1516
sandboxListSources,
1617
sandboxHcPkg,
@@ -59,36 +60,54 @@ import Distribution.Client.Targets ( UserTarget(..)
5960
, readUserTargets
6061
, resolveUserTargets )
6162
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 )
6367
import Distribution.Simple.Compiler ( Compiler(..), PackageDB(..)
6468
, PackageDBStack )
6569
import Distribution.Simple.Configure ( configCompilerAux
6670
, interpretPackageDbFlags )
71+
import Distribution.Simple.PreProcess ( knownSuffixHandlers )
6772
import Distribution.Simple.Program ( ProgramConfiguration )
6873
import Distribution.Simple.Setup ( Flag(..)
6974
, fromFlag, fromFlagOrDefault )
75+
import Distribution.Simple.SrcDist ( prepareTree )
7076
import Distribution.Simple.Utils ( die, debug, notice, info
71-
, debugNoWrap
77+
, debugNoWrap, defaultPackageDesc
7278
, intercalate
7379
, createDirectoryIfMissingVerbose )
80+
import Distribution.Package ( Package(..) )
7481
import Distribution.System ( Platform )
82+
import Distribution.Text ( display )
7583
import Distribution.Verbosity ( Verbosity, lessVerbose )
7684
import Distribution.Compat.Env ( lookupEnv, setEnv )
7785
import qualified Distribution.Client.Sandbox.Index as Index
7886
import qualified Distribution.Simple.Register as Register
7987
import Control.Exception ( assert, bracket_ )
80-
import Control.Monad ( unless, when )
88+
import Control.Monad ( forM, unless, when )
8189
import Data.IORef ( newIORef, writeIORef, readIORef )
8290
import Data.List ( (\\), delete )
8391
import Data.Monoid ( mempty, mappend )
84-
import System.Directory ( doesDirectoryExist
92+
import System.Directory ( createDirectory
93+
, doesDirectoryExist
8594
, getCurrentDirectory
8695
, removeDirectoryRecursive
87-
, removeFile )
96+
, removeFile
97+
, renameDirectory )
8898
import System.FilePath ( (</>), getSearchPath
8999
, searchPathSeparator )
90100

91101

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+
92111
--
93112
-- * Basic sandbox functions.
94113
--
@@ -220,12 +239,9 @@ sandboxDelete verbosity _sandboxFlags globalFlags = do
220239
notice verbosity $ "Deleting the sandbox located at " ++ sandboxDir
221240
removeDirectoryRecursive sandboxDir
222241

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
229245
let savedConfig = pkgEnvSavedConfig pkgEnv
230246
indexFile <- tryGetIndexFilePath savedConfig
231247

@@ -241,6 +257,63 @@ sandboxAddSource verbosity buildTreeRefs _sandboxFlags globalFlags = do
241257
Index.addBuildTreeRefs verbosity indexFile buildTreeRefs'
242258
return buildTreeRefs'
243259

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+
244317
-- | Entry point for the 'cabal sandbox delete-source' command.
245318
sandboxDeleteSource :: Verbosity -> [FilePath] -> SandboxFlags -> GlobalFlags
246319
-> IO ()

cabal-install/Distribution/Client/Sandbox/Timestamp.hs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ import Distribution.Simple.SrcDist (allSourcesBuildInfo,
3838
findMainExeFile,
3939
findSetupFile)
4040
import Distribution.Simple.Utils (defaultPackageDesc, die,
41-
findPackageDesc,
41+
debug, findPackageDesc,
4242
matchFileGlob, warn)
4343
import Distribution.System (Platform)
4444
import Distribution.Text (display)
4545
import Distribution.Verbosity (Verbosity)
4646

47-
import Distribution.Client.Utils (inDir)
47+
import Distribution.Client.Utils (inDir, tryCanonicalizePath)
4848
import Distribution.Client.Sandbox.Index (listBuildTreeRefs)
4949

5050
import Distribution.Compat.Exception (catchIO)
@@ -238,7 +238,8 @@ allPackageSourceFiles verbosity packageDir = inDir (Just packageDir) $ do
238238
mSetupFile <- findSetupFile
239239
descFile <- defaultPackageDesc verbosity
240240

241-
return . map (packageDir </>) $ descFile : (maybeToList mSetupFile)
241+
mapM tryCanonicalizePath . map (packageDir </>) $
242+
descFile : (maybeToList mSetupFile)
242243
++ incFiles ++ (concat extraSrcs) ++ (concat dataFs)
243244
++ (concat exeSources) ++ libSources
244245

@@ -266,7 +267,11 @@ isDepModified verbosity now (packageDir, timestamp) = do
266267
when (modTime > now) $
267268
warn verbosity $ "File '" ++ dep
268269
++ "' has a modification time that is in the future."
269-
if modTime >= timestamp then return True else go rest
270+
if modTime > timestamp
271+
then do
272+
debug verbosity ("Dependency has a modified source file: " ++ dep)
273+
return True
274+
else go rest
270275

271276
-- | Given an IO action, feed to it the list of modified add-source deps and
272277
-- set their timestamps to the current time in the timestamps file.

cabal-install/Distribution/Client/Setup.hs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,8 @@ instance Monoid Win32SelfUpgradeFlags where
12591259

12601260
data SandboxFlags = SandboxFlags {
12611261
sandboxVerbosity :: Flag Verbosity,
1262+
sandboxSnapshot :: Flag Bool, -- FIXME: this should be an 'add-source'-only
1263+
-- flag.
12621264
sandboxLocation :: Flag FilePath
12631265
}
12641266

@@ -1268,6 +1270,7 @@ defaultSandboxLocation = ".cabal-sandbox"
12681270
defaultSandboxFlags :: SandboxFlags
12691271
defaultSandboxFlags = SandboxFlags {
12701272
sandboxVerbosity = toFlag normal,
1273+
sandboxSnapshot = toFlag False,
12711274
sandboxLocation = toFlag defaultSandboxLocation
12721275
}
12731276

@@ -1289,6 +1292,11 @@ sandboxCommand = CommandUI {
12891292
[ optionVerbosity sandboxVerbosity
12901293
(\v flags -> flags { sandboxVerbosity = v })
12911294

1295+
, option [] ["snapshot"]
1296+
"Take a snapshot instead of creating a link (only applies to 'add-source')"
1297+
sandboxSnapshot (\v flags -> flags { sandboxSnapshot = v })
1298+
trueArg
1299+
12921300
, option [] ["sandbox"]
12931301
"Sandbox location (default: './.cabal-sandbox')."
12941302
sandboxLocation (\v flags -> flags { sandboxLocation = v })
@@ -1299,10 +1307,12 @@ sandboxCommand = CommandUI {
12991307
instance Monoid SandboxFlags where
13001308
mempty = SandboxFlags {
13011309
sandboxVerbosity = mempty,
1310+
sandboxSnapshot = mempty,
13021311
sandboxLocation = mempty
13031312
}
13041313
mappend a b = SandboxFlags {
13051314
sandboxVerbosity = combine sandboxVerbosity,
1315+
sandboxSnapshot = combine sandboxSnapshot,
13061316
sandboxLocation = combine sandboxLocation
13071317
}
13081318
where combine field = field a `mappend` field b

0 commit comments

Comments
 (0)