@@ -12,23 +12,29 @@ Types and functions related to Stack's @clean@ and @purge@ commands.
1212
1313module Stack.Clean
1414 ( CleanOpts (.. )
15+ , CleanDepth (.. )
1516 , CleanCommand (.. )
1617 , cleanCmd
1718 , clean
1819 ) where
1920
21+ import Control.Monad.Extra ( concatMapM )
2022import Data.List ( (\\) )
2123import qualified Data.Map.Strict as Map
22- import Path.IO ( ignoringAbsence , removeDirRecur )
24+ import Path ( (</>) , isProperPrefixOf )
25+ import Path.IO ( ignoringAbsence , listDirRecur , removeDirRecur )
2326import Stack.Config ( withBuildConfig )
24- import Stack.Constants.Config ( rootDistDirFromDir , workDirFromDir )
27+ import Stack.Constants.Config
28+ ( distRelativeDir , rootDistDirFromDir , workDirFromDir )
2529import Stack.Prelude
26- import Stack.Runners ( ShouldReexec (.. ), withConfig )
30+ import Stack.Runners
31+ ( ShouldReexec (.. ), withConfig , withDefaultEnvConfig )
2732import Stack.Types.BuildConfig
2833 ( BuildConfig (.. ), HasBuildConfig (.. ), getWorkDir )
2934import Stack.Types.Config ( Config )
35+ import Stack.Types.EnvConfig ( EnvConfig )
3036import Stack.Types.Runner ( Runner )
31- import Stack.Types.SourceMap ( SMWanted (.. ), ppRoot )
37+ import Stack.Types.SourceMap ( ProjectPackage , SMWanted (.. ), ppRoot )
3238
3339-- | Type representing \'pretty\' exceptions thrown by functions exported by the
3440-- "Stack.Clean" module.
@@ -64,7 +70,13 @@ instance Pretty CleanPrettyException where
6470instance Exception CleanPrettyException
6571
6672-- | 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
6880 = CleanShallow [PackageName ]
6981 -- ^ Delete the "dist directories" as defined in
7082 -- 'Stack.Constants.Config.distRelativeDir' for the given project packages.
@@ -84,7 +96,11 @@ cleanCmd = withConfig NoReexec . clean
8496-- | Deletes build artifacts in the current project.
8597clean :: CleanOpts -> RIO Config ()
8698clean 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
88104 logDebug $ " Need to delete: " <> fromString (show (map toFilePath toDelete))
89105 failures <- catMaybes <$> mapM cleanDir toDelete
90106 case failures of
@@ -97,20 +113,62 @@ cleanDir dir = do
97113 liftIO (ignoringAbsence (removeDirRecur dir) >> pure Nothing ) `catchAny` \ ex ->
98114 pure $ Just (dir, ex)
99115
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
102135 packages <- view $ buildConfigL . to (. smWanted. project)
103- case cleanOpts of
104- CleanShallow [] ->
136+ case depth of
137+ CleanShallow [] -> do
105138 -- 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
107141 CleanShallow targets -> do
108142 let localPkgNames = Map. keys packages
109143 getPkgDir pkgName' = fmap ppRoot (Map. lookup pkgName' packages)
144+ pkgNames = mapMaybe getPkgDir targets
110145 case targets \\ localPkgNames of
111- [] -> mapM rootDistDirFromDir (mapMaybe getPkgDir targets)
146+ [] -> concatMapM unusedRootDistDirsFromDir pkgNames
112147 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