@@ -12,23 +12,29 @@ Types and functions related to Stack's @clean@ and @purge@ commands.
12
12
13
13
module Stack.Clean
14
14
( CleanOpts (.. )
15
+ , CleanDepth (.. )
15
16
, CleanCommand (.. )
16
17
, cleanCmd
17
18
, clean
18
19
) where
19
20
21
+ import Control.Monad.Extra ( concatMapM )
20
22
import Data.List ( (\\) )
21
23
import qualified Data.Map.Strict as Map
22
- import Path.IO ( ignoringAbsence , removeDirRecur )
24
+ import Path ( (</>) , isProperPrefixOf )
25
+ import Path.IO ( ignoringAbsence , listDirRecur , removeDirRecur )
23
26
import Stack.Config ( withBuildConfig )
24
- import Stack.Constants.Config ( rootDistDirFromDir , workDirFromDir )
27
+ import Stack.Constants.Config
28
+ ( distRelativeDir , rootDistDirFromDir , workDirFromDir )
25
29
import Stack.Prelude
26
- import Stack.Runners ( ShouldReexec (.. ), withConfig )
30
+ import Stack.Runners
31
+ ( ShouldReexec (.. ), withConfig , withDefaultEnvConfig )
27
32
import Stack.Types.BuildConfig
28
33
( BuildConfig (.. ), HasBuildConfig (.. ), getWorkDir )
29
34
import Stack.Types.Config ( Config )
35
+ import Stack.Types.EnvConfig ( EnvConfig )
30
36
import Stack.Types.Runner ( Runner )
31
- import Stack.Types.SourceMap ( SMWanted (.. ), ppRoot )
37
+ import Stack.Types.SourceMap ( ProjectPackage , SMWanted (.. ), ppRoot )
32
38
33
39
-- | Type representing \'pretty\' exceptions thrown by functions exported by the
34
40
-- "Stack.Clean" module.
@@ -64,7 +70,13 @@ instance Pretty CleanPrettyException where
64
70
instance Exception CleanPrettyException
65
71
66
72
-- | Type representing command line options for the @stack clean@ command.
67
- data CleanOpts
73
+ data CleanOpts = CleanOpts
74
+ { depth :: ! CleanDepth
75
+ , omitThis :: ! Bool
76
+ }
77
+
78
+ -- | Type representing depths of cleaning for the @stack clean@ command.
79
+ data CleanDepth
68
80
= CleanShallow [PackageName ]
69
81
-- ^ Delete the "dist directories" as defined in
70
82
-- 'Stack.Constants.Config.distRelativeDir' for the given project packages.
@@ -84,7 +96,11 @@ cleanCmd = withConfig NoReexec . clean
84
96
-- | Deletes build artifacts in the current project.
85
97
clean :: CleanOpts -> RIO Config ()
86
98
clean cleanOpts = do
87
- toDelete <- withBuildConfig $ dirsToDelete cleanOpts
99
+ toDelete <- if cleanOpts. omitThis
100
+ then
101
+ withDefaultEnvConfig $ dirsToDeleteGivenConfig cleanOpts. depth
102
+ else
103
+ withBuildConfig $ dirsToDeleteSimple cleanOpts. depth
88
104
logDebug $ " Need to delete: " <> fromString (show (map toFilePath toDelete))
89
105
failures <- catMaybes <$> mapM cleanDir toDelete
90
106
case failures of
@@ -97,20 +113,62 @@ cleanDir dir = do
97
113
liftIO (ignoringAbsence (removeDirRecur dir) >> pure Nothing ) `catchAny` \ ex ->
98
114
pure $ Just (dir, ex)
99
115
100
- dirsToDelete :: CleanOpts -> RIO BuildConfig [Path Abs Dir ]
101
- dirsToDelete cleanOpts = do
116
+ dirsToDeleteSimple :: CleanDepth -> RIO BuildConfig [Path Abs Dir ]
117
+ dirsToDeleteSimple depth = do
118
+ packages <- view $ buildConfigL . to (. smWanted. project)
119
+ case depth of
120
+ CleanShallow [] -> do
121
+ -- Filter out packages listed as extra-deps
122
+ let pkgNames = Map. elems packages
123
+ mapM (rootDistDirFromDir . ppRoot) pkgNames
124
+ CleanShallow targets -> do
125
+ let localPkgNames = Map. keys packages
126
+ getPkgDir pkgName' = fmap ppRoot (Map. lookup pkgName' packages)
127
+ pkgNames = mapMaybe getPkgDir targets
128
+ case targets \\ localPkgNames of
129
+ [] -> mapM rootDistDirFromDir pkgNames
130
+ xs -> prettyThrowM (NonLocalPackages xs)
131
+ CleanFull -> allWorkDirs $ Map. elems packages
132
+
133
+ dirsToDeleteGivenConfig :: CleanDepth -> RIO EnvConfig [Path Abs Dir ]
134
+ dirsToDeleteGivenConfig depth = do
102
135
packages <- view $ buildConfigL . to (. smWanted. project)
103
- case cleanOpts of
104
- CleanShallow [] ->
136
+ case depth of
137
+ CleanShallow [] -> do
105
138
-- Filter out packages listed as extra-deps
106
- mapM (rootDistDirFromDir . ppRoot) $ Map. elems packages
139
+ let pkgNames = Map. elems packages
140
+ concatMapM (unusedRootDistDirsFromDir . ppRoot) pkgNames
107
141
CleanShallow targets -> do
108
142
let localPkgNames = Map. keys packages
109
143
getPkgDir pkgName' = fmap ppRoot (Map. lookup pkgName' packages)
144
+ pkgNames = mapMaybe getPkgDir targets
110
145
case targets \\ localPkgNames of
111
- [] -> mapM rootDistDirFromDir (mapMaybe getPkgDir targets)
146
+ [] -> concatMapM unusedRootDistDirsFromDir pkgNames
112
147
xs -> prettyThrowM (NonLocalPackages xs)
113
- CleanFull -> do
114
- pkgWorkDirs <- mapM (workDirFromDir . ppRoot) $ Map. elems packages
115
- projectWorkDir <- getWorkDir
116
- pure (projectWorkDir : pkgWorkDirs)
148
+ CleanFull -> allWorkDirs $ Map. elems packages
149
+
150
+ allWorkDirs :: HasBuildConfig env => [ProjectPackage ] -> RIO env [Path Abs Dir ]
151
+ allWorkDirs pps = do
152
+ pkgWorkDirs <- mapM (workDirFromDir . ppRoot) pps
153
+ projectWorkDir <- getWorkDir
154
+ pure (projectWorkDir : pkgWorkDirs)
155
+
156
+ unusedRootDistDirsFromDir :: Path Abs Dir -> RIO EnvConfig [Path Abs Dir ]
157
+ unusedRootDistDirsFromDir pkgDir = do
158
+ rootDistDir <- rootDistDirFromDir pkgDir
159
+ omitDir <- fmap (pkgDir </> ) distRelativeDir
160
+ allDirsOmittingDirs rootDistDir omitDir
161
+
162
+ allDirsOmittingDirs ::
163
+ MonadIO m
164
+ => Path Abs Dir
165
+ -> Path Abs Dir
166
+ -> m [Path Abs Dir ]
167
+ allDirsOmittingDirs topDir subDir = do
168
+ allDirs <- (topDir : ) . fst <$> listDirRecur topDir
169
+ let isNotInSubDir dir = not
170
+ ( isProperPrefixOf dir subDir
171
+ || subDir == dir
172
+ || isProperPrefixOf subDir dir
173
+ )
174
+ pure $ filter isNotInSubDir allDirs
0 commit comments