diff --git a/ChangeLog.md b/ChangeLog.md index 9069219be9..fe1af6c780 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -116,6 +116,8 @@ Other enhancements: * `stack clean` will delete the entire `.stack-work/dist` directory, not just the relevant subdirectory for the current GHC version. See [#4480](https://github.com/commercialhaskell/stack/issues/4480). +* Add `stack purge` as a shortcut for `stack clean --full`. See + [#3863](https://github.com/commercialhaskell/stack/issues/3863). Bug fixes: diff --git a/doc/GUIDE.md b/doc/GUIDE.md index 850cf64fbd..1250832e04 100644 --- a/doc/GUIDE.md +++ b/doc/GUIDE.md @@ -280,6 +280,24 @@ As you can see from that path (and as emphasized earlier), the installation is placed to not interfere with any other GHC installation, whether system-wide or even different GHC versions installed by stack. +## Cleaning your project + +You can clean up build artifacts for your project using the `stack clean` and `stack purge` commands. + +### `stack clean` + +`stack clean` deletes the local working directories containing compiler output. +By default, that means the contents of directories in `.stack-work/dist`, for all the `.stack-work` directories within a project. + +Use `stack clean ` to delete the output for the package _specific-package_ only. + +### `stack purge` + +`stack purge` deletes the local stack working directories, including extra-deps, git dependencies and the compiler output (including logs). +It does not delete any snapshot packages, compilers or programs installed using `stack install`. This essentially +reverts the project to a completely fresh state, as if it had never been built. +`stack purge` is just a shortcut for `stack clean --full` + ### The build command The build command is the heart and soul of stack. It is the engine that powers diff --git a/src/Stack/Clean.hs b/src/Stack/Clean.hs index 6a8087649f..ef4b58fdae 100644 --- a/src/Stack/Clean.hs +++ b/src/Stack/Clean.hs @@ -8,6 +8,7 @@ module Stack.Clean (clean ,CleanOpts(..) + ,CleanCommand(..) ,StackCleanException(..) ) where @@ -58,12 +59,17 @@ dirsToDelete cleanOpts = do -- | Options for @stack clean@. data CleanOpts = CleanShallow [PackageName] - -- ^ Delete the "dist directories" as defined in 'Stack.Constants.distRelativeDir' + -- ^ Delete the "dist directories" as defined in 'Stack.Constants.Config.distRelativeDir' -- for the given local packages. If no packages are given, all project packages -- should be cleaned. | CleanFull -- ^ Delete all work directories in the project. +-- | Clean commands +data CleanCommand + = Clean + | Purge + -- | Exceptions during cleanup. newtype StackCleanException = NonLocalPackages [PackageName] diff --git a/src/Stack/Options/CleanParser.hs b/src/Stack/Options/CleanParser.hs index de566e9638..b90845ff05 100644 --- a/src/Stack/Options/CleanParser.hs +++ b/src/Stack/Options/CleanParser.hs @@ -2,21 +2,23 @@ module Stack.Options.CleanParser where import Options.Applicative -import Stack.Clean (CleanOpts (..)) +import Stack.Clean (CleanCommand(..), CleanOpts (..)) import Stack.Prelude import Stack.Types.PackageName -- | Command-line parser for the clean command. -cleanOptsParser :: Parser CleanOpts -cleanOptsParser = CleanShallow <$> packages <|> doFullClean +cleanOptsParser :: CleanCommand -> Parser CleanOpts +cleanOptsParser Clean = CleanShallow <$> packages <|> doFullClean where packages = many (packageNameArgument (metavar "PACKAGE" <> - help "If none specified, clean all local packages")) + help "If none specified, clean all project packages")) doFullClean = flag' CleanFull (long "full" <> - help "Delete all work directories (.stack-work by default) in the project") + help "Delete the project’s stack working directories (.stack-work by default).") + +cleanOptsParser Purge = pure CleanFull diff --git a/src/main/Main.hs b/src/main/Main.hs index 53834746e6..22c63afc70 100644 --- a/src/main/Main.hs +++ b/src/main/Main.hs @@ -54,7 +54,7 @@ import RIO.PrettyPrint import qualified RIO.PrettyPrint as PP (style) import Stack.Build import Stack.Build.Target (NeedTargets(..)) -import Stack.Clean (CleanOpts(..), clean) +import Stack.Clean (CleanCommand(..), CleanOpts(..), clean) import Stack.Config import Stack.ConfigCmd as ConfigCmd import Stack.Constants @@ -410,9 +410,13 @@ commandLineHandler currentDir progName isInterpreter = complicatedOptions evalCmd (evalOptsParser "CODE") addCommand' "clean" - "Clean the local packages" + "Delete build artefacts for the project packages." cleanCmd - cleanOptsParser + (cleanOptsParser Clean) + addCommand' "purge" + "Delete the project stack working directories (.stack-work by default). Shortcut for 'stack clean --full'" + cleanCmd + (cleanOptsParser Purge) addCommand' "list-dependencies" "List the dependencies" (listDependenciesCmd True) diff --git a/test/integration/tests/3863-purge-command/Main.hs b/test/integration/tests/3863-purge-command/Main.hs new file mode 100644 index 0000000000..4c54e19faa --- /dev/null +++ b/test/integration/tests/3863-purge-command/Main.hs @@ -0,0 +1,39 @@ +import StackTest +import Data.Maybe (listToMaybe, fromMaybe) +import System.Directory +import System.FilePath + +main :: IO () +main = + -- For these commands, we'll need to know the `dist` directory. + -- This is usually `.stack-work/dist/$compiler-variant/Cabal-xxxx` + stackCheckStdout [defaultResolverArg, "path", "--dist-dir"] $ \distDir -> + + stackCheckStdout [defaultResolverArg, "path", "--local-install-root"] $ \localInstallRoot -> do + + -- Usually `.stack-work` + let stackWork = fromMaybe (error "There must be a stack working directory.") $ + listToMaybe (splitDirectories distDir) + + -- First, clean the .stack-work directory. + -- This is only necessary when running individual tests. + stack [defaultResolverArg, "purge"] + doesNotExist stackWork + + -- The dist directory should exist after a build + stack [defaultResolverArg, "build"] + doesExist distDir + doesExist localInstallRoot + doesExist stackWork + + -- The dist directory should not exist after a clean, whereas the + -- .stack-work directory should + stack [defaultResolverArg, "clean"] + run "exa" ["-T", ".stack-work"] + doesNotExist distDir + doesExist localInstallRoot + doesExist stackWork + + -- The .stack-work directory should not exist after a purge + stack [defaultResolverArg, "purge"] + doesNotExist stackWork diff --git a/test/integration/tests/3863-purge-command/files/new-template.cabal b/test/integration/tests/3863-purge-command/files/new-template.cabal new file mode 100644 index 0000000000..192e0b2dfb --- /dev/null +++ b/test/integration/tests/3863-purge-command/files/new-template.cabal @@ -0,0 +1,11 @@ +name: new-template +version: 0.1.0.0 +build-type: Simple +cabal-version: >=1.10 + + +library + hs-source-dirs: src + exposed-modules: Lib + build-depends: base >= 4.7 && < 5 + default-language: Haskell2010 diff --git a/test/integration/tests/3863-purge-command/files/src/Lib.hs b/test/integration/tests/3863-purge-command/files/src/Lib.hs new file mode 100644 index 0000000000..1c88a82644 --- /dev/null +++ b/test/integration/tests/3863-purge-command/files/src/Lib.hs @@ -0,0 +1,4 @@ +module Lib where + +someFunc :: () +someFunc = () diff --git a/test/integration/tests/3863-purge-command/files/stack.yaml b/test/integration/tests/3863-purge-command/files/stack.yaml new file mode 100644 index 0000000000..227c646ed3 --- /dev/null +++ b/test/integration/tests/3863-purge-command/files/stack.yaml @@ -0,0 +1,5 @@ +flags: {} +packages: +- '.' +extra-deps: [] +resolver: lts-11.22