Skip to content

Commit 04bab92

Browse files
committed
Re #6771 Add --[no-]omit-this to stack clean
1 parent 770df2f commit 04bab92

File tree

5 files changed

+106
-27
lines changed

5 files changed

+106
-27
lines changed

ChangeLog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ Other enhancements:
2727
* From GHC 9.12.1, `base` is not a GHC wired-in package. In configuration files,
2828
the `notify-if-base-not-boot` key is introduced, to allow the exisitng
2929
notification to be muted if unwanted when using such GHC versions.
30+
* Add flag `--[no-]omit-this` (default: disabled) to Stack's `clean` command to
31+
omit directories currently in use from cleaning (when `--full` is not
32+
specified).
3033

3134
Bug fixes:
3235

doc/commands/clean_command.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Either
66

77
~~~text
8-
stack clean [PACKAGE]
8+
stack clean [PACKAGE] [--[no-]omit-this]
99
~~~
1010

1111
or
@@ -14,8 +14,17 @@ or
1414
stack clean --full
1515
~~~
1616

17-
`stack clean` deletes build artefacts for one or more project packages specified
18-
as arguments. If no project packages are specified, all project packages are
19-
cleaned.
17+
`stack clean` deletes build artefacts for one or more project packages.
2018

21-
`stack clean --full` deletes the project's Stack working directory.
19+
By default:
20+
21+
* all project packages are cleaned. Pass one or more project package names to
22+
specify individual project packages; and
23+
24+
* the `dist` directory and all of its subdirectories in the Stack work directory
25+
for each relevant project package are deleted. Pass the flag `--omit-this` to
26+
omit, from cleaning, the `dist` work directory (see `stack path --dist-dir`)
27+
and its subdirectories currently in use.
28+
29+
`stack clean --full` deletes the Stack work directories of the project and its
30+
project packages.

src/Stack/CLI.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ commandLineHandler currentDir progName mExecutablePath isInterpreter =
230230

231231
clean = addCommand'
232232
"clean"
233-
"Delete build artefacts for the project packages."
233+
"Delete build artefacts for project packages."
234234
cleanCmd
235235
(cleanOptsParser Clean)
236236

src/Stack/Clean.hs

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,26 @@ Types and functions related to Stack's @clean@ and @purge@ commands.
1212

1313
module Stack.Clean
1414
( CleanOpts (..)
15+
, CleanDepth (..)
1516
, CleanCommand (..)
1617
, cleanCmd
1718
, clean
1819
) where
1920

21+
import Control.Monad.Extra ( concatMapM )
2022
import Data.List ( (\\) )
2123
import qualified Data.Map.Strict as Map
22-
import Path.IO ( ignoringAbsence, removeDirRecur )
23-
import Stack.Config ( withBuildConfig )
24-
import Stack.Constants.Config ( rootDistDirFromDir, workDirFromDir )
24+
import Path ( (</>), isProperPrefixOf )
25+
import Path.IO ( ignoringAbsence, listDirRecur, removeDirRecur )
26+
import Stack.Constants.Config
27+
( distRelativeDir, rootDistDirFromDir, workDirFromDir )
2528
import Stack.Prelude
26-
import Stack.Runners ( ShouldReexec (..), withConfig )
29+
import Stack.Runners
30+
( ShouldReexec (..), withConfig, withDefaultEnvConfig )
2731
import Stack.Types.BuildConfig
2832
( BuildConfig (..), HasBuildConfig (..), getWorkDir )
2933
import Stack.Types.Config ( Config )
34+
import Stack.Types.EnvConfig ( EnvConfig )
3035
import Stack.Types.Runner ( Runner )
3136
import Stack.Types.SourceMap ( SMWanted (..), ppRoot )
3237

@@ -64,7 +69,13 @@ instance Pretty CleanPrettyException where
6469
instance Exception CleanPrettyException
6570

6671
-- | Type representing command line options for the @stack clean@ command.
67-
data CleanOpts
72+
data CleanOpts = CleanOpts
73+
{ depth :: !CleanDepth
74+
, omitThis :: !Bool
75+
}
76+
77+
-- | Type representing depths of cleaning for the @stack clean@ command.
78+
data CleanDepth
6879
= CleanShallow [PackageName]
6980
-- ^ Delete the "dist directories" as defined in
7081
-- 'Stack.Constants.Config.distRelativeDir' for the given project packages.
@@ -84,7 +95,7 @@ cleanCmd = withConfig NoReexec . clean
8495
-- | Deletes build artifacts in the current project.
8596
clean :: CleanOpts -> RIO Config ()
8697
clean cleanOpts = do
87-
toDelete <- withBuildConfig $ dirsToDelete cleanOpts
98+
toDelete <- withDefaultEnvConfig $ dirsToDelete cleanOpts
8899
logDebug $ "Need to delete: " <> fromString (show (map toFilePath toDelete))
89100
failures <- catMaybes <$> mapM cleanDir toDelete
90101
case failures of
@@ -97,20 +108,50 @@ cleanDir dir = do
97108
liftIO (ignoringAbsence (removeDirRecur dir) >> pure Nothing) `catchAny` \ex ->
98109
pure $ Just (dir, ex)
99110

100-
dirsToDelete :: CleanOpts -> RIO BuildConfig [Path Abs Dir]
111+
dirsToDelete :: CleanOpts -> RIO EnvConfig [Path Abs Dir]
101112
dirsToDelete cleanOpts = do
102113
packages <- view $ buildConfigL . to (.smWanted.project)
103114
case cleanOpts of
104-
CleanShallow [] ->
115+
(CleanOpts (CleanShallow []) omitThis) -> do
105116
-- Filter out packages listed as extra-deps
106-
mapM (rootDistDirFromDir . ppRoot) $ Map.elems packages
107-
CleanShallow targets -> do
117+
let pkgNames = Map.elems packages
118+
if omitThis
119+
then
120+
concatMapM (unusedRootDistDirsFromDir . ppRoot) pkgNames
121+
else
122+
mapM (rootDistDirFromDir . ppRoot) pkgNames
123+
(CleanOpts (CleanShallow targets) omitThis) -> do
108124
let localPkgNames = Map.keys packages
109125
getPkgDir pkgName' = fmap ppRoot (Map.lookup pkgName' packages)
126+
pkgNames = mapMaybe getPkgDir targets
110127
case targets \\ localPkgNames of
111-
[] -> mapM rootDistDirFromDir (mapMaybe getPkgDir targets)
128+
[] -> if omitThis
129+
then
130+
concatMapM unusedRootDistDirsFromDir pkgNames
131+
else
132+
mapM rootDistDirFromDir pkgNames
112133
xs -> prettyThrowM (NonLocalPackages xs)
113-
CleanFull -> do
134+
(CleanOpts CleanFull _) -> do
114135
pkgWorkDirs <- mapM (workDirFromDir . ppRoot) $ Map.elems packages
115136
projectWorkDir <- getWorkDir
116137
pure (projectWorkDir : pkgWorkDirs)
138+
139+
unusedRootDistDirsFromDir :: Path Abs Dir -> RIO EnvConfig [Path Abs Dir]
140+
unusedRootDistDirsFromDir pkgDir = do
141+
rootDistDir <- rootDistDirFromDir pkgDir
142+
omitDir <- fmap (pkgDir </>) distRelativeDir
143+
allDirsOmittingDirs rootDistDir omitDir
144+
145+
allDirsOmittingDirs ::
146+
MonadIO m
147+
=> Path Abs Dir
148+
-> Path Abs Dir
149+
-> m [Path Abs Dir]
150+
allDirsOmittingDirs topDir subDir = do
151+
allDirs <- (topDir :) <$> fst <$> listDirRecur topDir
152+
let isNotInSubDir dir = not
153+
( isProperPrefixOf dir subDir
154+
|| subDir == dir
155+
|| isProperPrefixOf subDir dir
156+
)
157+
pure $ filter isNotInSubDir allDirs

src/Stack/Options/CleanParser.hs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{-# LANGUAGE NoImplicitPrelude #-}
2+
{-# LANGUAGE ApplicativeDo #-}
23

34
{-|
45
Module : Stack.Options.CleanParser
@@ -9,25 +10,50 @@ module Stack.Options.CleanParser
910
( cleanOptsParser
1011
) where
1112

12-
import Options.Applicative ( Parser, flag', help, long, metavar )
13-
import Stack.Clean ( CleanCommand (..), CleanOpts (..) )
13+
import Options.Applicative ( Parser, flag', help, idm, long, metavar )
14+
import Options.Applicative.Builder.Extra ( boolFlags )
15+
import Stack.Clean
16+
( CleanCommand (..), CleanDepth (..), CleanOpts (..) )
1417
import Stack.Prelude
1518
import Stack.Types.PackageName ( packageNameArgument )
1619

1720
-- | Command-line parser for the clean command.
1821
cleanOptsParser :: CleanCommand -> Parser CleanOpts
19-
cleanOptsParser Clean = CleanShallow
20-
<$> packages
21-
<|> doFullClean
22+
cleanOptsParser Clean = shallowParser <|> fullParser
23+
24+
cleanOptsParser Purge = pure $ CleanOpts
25+
{ depth = CleanFull
26+
, omitThis = False
27+
}
28+
29+
shallowParser :: Parser CleanOpts
30+
shallowParser = do
31+
packages <- parsePackages
32+
omitThis <- parseOmitThis
33+
pure $ CleanOpts
34+
{ depth = CleanShallow packages
35+
, omitThis
36+
}
2237
where
23-
packages = many (packageNameArgument
38+
parsePackages = many (packageNameArgument
2439
( metavar "PACKAGE"
2540
<> help "If none specified, clean all project packages."
2641
))
42+
parseOmitThis = boolFlags False
43+
"omit-this"
44+
"the omission of directories currently in use"
45+
idm
46+
47+
fullParser :: Parser CleanOpts
48+
fullParser = do
49+
depth <- doFullClean
50+
pure $ CleanOpts
51+
{ depth
52+
, omitThis = False
53+
}
54+
where
2755
doFullClean = flag' CleanFull
2856
( long "full"
29-
<> help "Delete the project's Stack working directories (.stack-work by \
57+
<> help "Delete the project's Stack work directories (.stack-work by \
3058
\default)."
3159
)
32-
33-
cleanOptsParser Purge = pure CleanFull

0 commit comments

Comments
 (0)