@@ -15,6 +15,9 @@ module Distribution.Client.ProjectPlanOutput
15
15
, createPackageEnvironment
16
16
, writePlanGhcEnvironment
17
17
, argsEquivalentOfGhcEnvironmentFile
18
+
19
+ -- * Store garbage collection
20
+ , writeGcRoot
18
21
) where
19
22
20
23
import Distribution.Client.DistDirLayout
@@ -36,6 +39,7 @@ import qualified Distribution.Solver.Types.ComponentDeps as ComponentDeps
36
39
import qualified Distribution.Compat.Binary as Binary
37
40
import Distribution.Compat.Graph (Graph , Node )
38
41
import qualified Distribution.Compat.Graph as Graph
42
+ import Distribution.Compiler (AbiTag (.. ), CompilerFlavor (.. ))
39
43
import Distribution.InstalledPackageInfo (InstalledPackageInfo )
40
44
import Distribution.Package
41
45
import qualified Distribution.PackageDescription as PD
@@ -45,13 +49,28 @@ import Distribution.Simple.BuildPaths
45
49
, exeExtension
46
50
)
47
51
import Distribution.Simple.Compiler
52
+ ( Compiler (compilerAbiTag )
53
+ , CompilerId (.. )
54
+ , GlobalPackageDB
55
+ , PackageDB (.. )
56
+ , PackageDBCWD
57
+ , PackageDBStack
58
+ , PackageDBStackCWD
59
+ , SpecificPackageDB
60
+ , UserPackageDB
61
+ , compilerFlavor
62
+ , compilerId
63
+ , compilerVersion
64
+ , showCompilerId
65
+ )
48
66
import Distribution.Simple.GHC
49
67
( GhcEnvironmentFileEntry (.. )
50
68
, GhcImplInfo (supportsPkgEnvFiles )
51
69
, getImplInfo
52
70
, simpleGhcEnvironmentFile
53
71
, writeGhcEnvironmentFile
54
72
)
73
+ import Distribution.Simple.Program.GHC (packageDbArgsDb )
55
74
import Distribution.Simple.Utils
56
75
import Distribution.System
57
76
import Distribution.Types.Version
@@ -61,8 +80,10 @@ import Distribution.Utils.Path hiding
61
80
( (<.>)
62
81
, (</>)
63
82
)
83
+ import Distribution.Utils.String (encodeStringUtf8 )
64
84
import Distribution.Verbosity
65
85
86
+ import Distribution.Client.Compat.Directory (createFileLink )
66
87
import Distribution.Client.Compat.Prelude
67
88
import Prelude ()
68
89
@@ -71,10 +92,12 @@ import qualified Data.ByteString.Lazy as BS
71
92
import qualified Data.Map as Map
72
93
import qualified Data.Set as Set
73
94
95
+ import Control.Exception (handleJust )
96
+ import Data.Containers.ListUtils (nubOrd )
97
+ import System.Directory (removeFile )
74
98
import System.FilePath
75
99
import System.IO
76
-
77
- import Distribution.Simple.Program.GHC (packageDbArgsDb )
100
+ import System.IO.Error (isDoesNotExistError )
78
101
79
102
-----------------------------------------------------------------------------
80
103
-- Writing plan.json files
@@ -1016,3 +1039,50 @@ relativePackageDBPath relroot pkgdb =
1016
1039
SpecificPackageDB path -> SpecificPackageDB relpath
1017
1040
where
1018
1041
relpath = makeRelative (normalise relroot) path
1042
+
1043
+ -- | Establish backlinks for garbage collection of the store
1044
+ writeGcRoot
1045
+ :: Verbosity
1046
+ -> StoreDirLayout
1047
+ -> DistDirLayout
1048
+ -> ElaboratedSharedConfig
1049
+ -> ElaboratedInstallPlan
1050
+ -> IO ()
1051
+ writeGcRoot verbosity storeDirLayout distDirLayout elaboratedSharedConfig elaboratedInstallPlan = do
1052
+ -- NOTE: this needs some thinking
1053
+ -- We need to establish backlinks for the store so that we can collect garbage later on.
1054
+ -- We have the whole build graph here so, to be pragmatic we are going to list all the
1055
+ -- non-inplace units in the plan, irrespectively of whether they are direct or transitive
1056
+ -- dependencies.
1057
+ let refsUnitIds =
1058
+ [ elabUnitId elab
1059
+ | InstallPlan. Configured elab <- InstallPlan. toList elaboratedInstallPlan
1060
+ , not (isInplaceBuildStyle (elabBuildStyle elab))
1061
+ ]
1062
+ writeFile referencesFile $ unlines $ map unUnitId $ nubOrd refsUnitIds
1063
+
1064
+ -- Write the gc root
1065
+ createDirectoryIfMissingVerbose verbosity True storeGcRootsDir
1066
+
1067
+ -- To avoid collision we name the link with the hash of the dist directory.
1068
+ let gcRootPath = storeGcRootsDir </> showHashValue (hashValue (encodePath distDir))
1069
+
1070
+ handleJust (\ e -> if isDoesNotExistError e then Just () else Nothing ) mempty $
1071
+ removeFile gcRootPath
1072
+
1073
+ createFileLink distDir gcRootPath
1074
+ where
1075
+ storeGcRootsDir = storeGcRootsDirectory storeDirLayout
1076
+ distDir = distDirectory distDirLayout
1077
+ referencesFile = distProjectCacheFile distDirLayout " store-refs-" <> compilerTag
1078
+ compiler = pkgConfigCompiler elaboratedSharedConfig
1079
+ -- NOTE: It would be a good idea to expose this in StoreDirLayoyt
1080
+ compilerTag = case compilerAbiTag compiler of
1081
+ NoAbiTag -> prettyShow (compilerId compiler)
1082
+ AbiTag tag -> prettyShow (compilerId compiler) <> " -" <> tag
1083
+
1084
+ -- NOTE: A FilePath should never represented as a String as we should never
1085
+ -- have to do this. Nevetheless we do not need this to be stable as changes
1086
+ -- will only mean a new root is created in place of the old one. Two roots
1087
+ -- pointing to the same directory should never be a problem.
1088
+ encodePath = BS. pack . encodeStringUtf8
0 commit comments