From f54b8076ed89e19dc2d67871542fe2bdb61c1914 Mon Sep 17 00:00:00 2001 From: noiioiu Date: Mon, 28 Oct 2024 16:02:08 -0500 Subject: [PATCH 01/15] Catch exception if git is not installed --- .../Client/Init/NonInteractive/Heuristics.hs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs index 138f9684553..16cdbbda576 100644 --- a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs +++ b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs @@ -1,4 +1,5 @@ {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE TypeApplications #-} ----------------------------------------------------------------------------- @@ -163,16 +164,18 @@ guessAuthorName = guessGitInfo "user.name" guessAuthorEmail :: Interactive m => m (Maybe String) guessAuthorEmail = guessGitInfo "user.email" -guessGitInfo :: Interactive m => String -> m (Maybe String) -guessGitInfo target = do - localInfo <- readProcessWithExitCode "git" ["config", "--local", target] "" - if null $ snd' localInfo - then do - globalInfo <- readProcessWithExitCode "git" ["config", "--global", target] "" - case fst' globalInfo of - ExitSuccess -> return $ Just (trim $ snd' globalInfo) - _ -> return Nothing - else return $ Just (trim $ snd' localInfo) +guessGitInfo :: String -> IO (Maybe String) +guessGitInfo target = + ( do + localInfo <- readProcessWithExitCode "git" ["config", "--local", target] "" + if null $ snd' localInfo + then do + globalInfo <- readProcessWithExitCode "git" ["config", "--global", target] "" + case fst' globalInfo of + ExitSuccess -> return $ Just (trim $ snd' globalInfo) + _ -> return Nothing + else return $ Just (trim $ snd' localInfo) + ) `catch` const @_ @IOError (pure Nothing) where fst' (x, _, _) = x snd' (_, x, _) = x From cbfae50109a8c3cc99720df89d9e39b521dd53ab Mon Sep 17 00:00:00 2001 From: noiioiu Date: Mon, 28 Oct 2024 16:07:37 -0500 Subject: [PATCH 02/15] fix formatting --- .../src/Distribution/Client/Init/NonInteractive/Heuristics.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs index 16cdbbda576..8527811cb0b 100644 --- a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs +++ b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs @@ -175,7 +175,8 @@ guessGitInfo target = ExitSuccess -> return $ Just (trim $ snd' globalInfo) _ -> return Nothing else return $ Just (trim $ snd' localInfo) - ) `catch` const @_ @IOError (pure Nothing) + ) + `catch` const @_ @IOError (pure Nothing) where fst' (x, _, _) = x snd' (_, x, _) = x From e7b20d0af56ca5cb47556320476e5a49723bf094 Mon Sep 17 00:00:00 2001 From: noiioiu Date: Mon, 28 Oct 2024 16:29:30 -0500 Subject: [PATCH 03/15] change type from IO to m --- .../src/Distribution/Client/Init/NonInteractive/Heuristics.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs index 8527811cb0b..a6888c084a1 100644 --- a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs +++ b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs @@ -164,7 +164,7 @@ guessAuthorName = guessGitInfo "user.name" guessAuthorEmail :: Interactive m => m (Maybe String) guessAuthorEmail = guessGitInfo "user.email" -guessGitInfo :: String -> IO (Maybe String) +guessGitInfo :: Interactive m => String -> m (Maybe String) guessGitInfo target = ( do localInfo <- readProcessWithExitCode "git" ["config", "--local", target] "" From 3838dfa677f4eee8905963828ea1bc52d1994668 Mon Sep 17 00:00:00 2001 From: noiioiu Date: Mon, 28 Oct 2024 17:10:35 -0500 Subject: [PATCH 04/15] add maybeReadProcessWithExitCode --- .../Client/Init/NonInteractive/Heuristics.hs | 22 ++++++++----------- .../src/Distribution/Client/Init/Types.hs | 3 +++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs index a6888c084a1..138f9684553 100644 --- a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs +++ b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs @@ -1,5 +1,4 @@ {-# LANGUAGE LambdaCase #-} -{-# LANGUAGE TypeApplications #-} ----------------------------------------------------------------------------- @@ -165,18 +164,15 @@ guessAuthorEmail :: Interactive m => m (Maybe String) guessAuthorEmail = guessGitInfo "user.email" guessGitInfo :: Interactive m => String -> m (Maybe String) -guessGitInfo target = - ( do - localInfo <- readProcessWithExitCode "git" ["config", "--local", target] "" - if null $ snd' localInfo - then do - globalInfo <- readProcessWithExitCode "git" ["config", "--global", target] "" - case fst' globalInfo of - ExitSuccess -> return $ Just (trim $ snd' globalInfo) - _ -> return Nothing - else return $ Just (trim $ snd' localInfo) - ) - `catch` const @_ @IOError (pure Nothing) +guessGitInfo target = do + localInfo <- readProcessWithExitCode "git" ["config", "--local", target] "" + if null $ snd' localInfo + then do + globalInfo <- readProcessWithExitCode "git" ["config", "--global", target] "" + case fst' globalInfo of + ExitSuccess -> return $ Just (trim $ snd' globalInfo) + _ -> return Nothing + else return $ Just (trim $ snd' localInfo) where fst' (x, _, _) = x snd' (_, x, _) = x diff --git a/cabal-install/src/Distribution/Client/Init/Types.hs b/cabal-install/src/Distribution/Client/Init/Types.hs index 0887cb54a71..8cacaf429ad 100644 --- a/cabal-install/src/Distribution/Client/Init/Types.hs +++ b/cabal-install/src/Distribution/Client/Init/Types.hs @@ -346,6 +346,7 @@ class Monad m => Interactive m where doesFileExist :: FilePath -> m Bool canonicalizePathNoThrow :: FilePath -> m FilePath readProcessWithExitCode :: FilePath -> [String] -> String -> m (ExitCode, String, String) + maybeReadProcessWithExitCode :: FilePath -> [String] -> String -> m (Maybe (ExitCode, String, String)) getEnvironment :: m [(String, String)] getCurrentYear :: m Integer listFilesInside :: (FilePath -> m Bool) -> FilePath -> m [FilePath] @@ -389,6 +390,7 @@ instance Interactive PromptIO where doesFileExist = liftIO <$> P.doesFileExist canonicalizePathNoThrow = liftIO <$> P.canonicalizePathNoThrow readProcessWithExitCode a b c = liftIO $ Process.readProcessWithExitCode a b c + maybeReadProcessWithExitCode a b c = liftIO $ (Just <$> Process.readProcessWithExitCode a b c) `catch` const @_ @IOError (pure Nothing) getEnvironment = liftIO P.getEnvironment getCurrentYear = liftIO P.getCurrentYear listFilesInside test dir = do @@ -438,6 +440,7 @@ instance Interactive PurePrompt where readProcessWithExitCode !_ !_ !_ = do input <- pop return (ExitSuccess, input, "") + maybeReadProcessWithExitCode = Just <$> readProcessWithExitCode getEnvironment = fmap (map read) popList getCurrentYear = fmap read pop listFilesInside pred' !_ = do From 121be52be6ca4c38a178d70d1abf45611c6bc29e Mon Sep 17 00:00:00 2001 From: noiioiu Date: Mon, 28 Oct 2024 17:19:54 -0500 Subject: [PATCH 05/15] use maybeReadProcessWithExitCode --- .../Client/Init/NonInteractive/Heuristics.hs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs index 138f9684553..e6838aa2e45 100644 --- a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs +++ b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs @@ -165,14 +165,14 @@ guessAuthorEmail = guessGitInfo "user.email" guessGitInfo :: Interactive m => String -> m (Maybe String) guessGitInfo target = do - localInfo <- readProcessWithExitCode "git" ["config", "--local", target] "" - if null $ snd' localInfo - then do - globalInfo <- readProcessWithExitCode "git" ["config", "--global", target] "" - case fst' globalInfo of - ExitSuccess -> return $ Just (trim $ snd' globalInfo) - _ -> return Nothing - else return $ Just (trim $ snd' localInfo) - where - fst' (x, _, _) = x - snd' (_, x, _) = x + localInfo <- maybeReadProcessWithExitCode "git" ["config", "--local", target] "" + case localInfo of + Nothing -> return Nothing + Just (_, localStdout, _) -> + if null localStdout + then do + globalInfo <- maybeReadProcessWithExitCode "git" ["config", "--global", target] "" + case globalInfo of + Just (ExitSuccess, globalStdout, _) -> return $ Just (trim globalStdout) + _ -> return Nothing + else return $ Just (trim localStdout) From a4953f4a2ff70323f92116e13b2e4311d2a3d7b2 Mon Sep 17 00:00:00 2001 From: noiioiu Date: Mon, 28 Oct 2024 17:38:07 -0500 Subject: [PATCH 06/15] disambiguate P.catch --- cabal-install/src/Distribution/Client/Init/Types.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cabal-install/src/Distribution/Client/Init/Types.hs b/cabal-install/src/Distribution/Client/Init/Types.hs index 8cacaf429ad..7a8499bf7ac 100644 --- a/cabal-install/src/Distribution/Client/Init/Types.hs +++ b/cabal-install/src/Distribution/Client/Init/Types.hs @@ -390,7 +390,7 @@ instance Interactive PromptIO where doesFileExist = liftIO <$> P.doesFileExist canonicalizePathNoThrow = liftIO <$> P.canonicalizePathNoThrow readProcessWithExitCode a b c = liftIO $ Process.readProcessWithExitCode a b c - maybeReadProcessWithExitCode a b c = liftIO $ (Just <$> Process.readProcessWithExitCode a b c) `catch` const @_ @IOError (pure Nothing) + maybeReadProcessWithExitCode a b c = liftIO $ (Just <$> Process.readProcessWithExitCode a b c) `P.catch` const @_ @IOError (pure Nothing) getEnvironment = liftIO P.getEnvironment getCurrentYear = liftIO P.getCurrentYear listFilesInside test dir = do From fe8cb2a43e6c77340d02afb436b1a31dff0d4900 Mon Sep 17 00:00:00 2001 From: noiioiu Date: Mon, 28 Oct 2024 17:47:52 -0500 Subject: [PATCH 07/15] add TypeApplications pragma --- cabal-install/src/Distribution/Client/Init/Types.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/cabal-install/src/Distribution/Client/Init/Types.hs b/cabal-install/src/Distribution/Client/Init/Types.hs index 7a8499bf7ac..93df5800983 100644 --- a/cabal-install/src/Distribution/Client/Init/Types.hs +++ b/cabal-install/src/Distribution/Client/Init/Types.hs @@ -3,6 +3,7 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE TypeApplications #-} -- | -- Module : Distribution.Client.Init.Types From 0689e02bc52a4264528c4abf52dac91c3a1e853c Mon Sep 17 00:00:00 2001 From: noiioiu Date: Mon, 28 Oct 2024 17:57:29 -0500 Subject: [PATCH 08/15] add missing arguments --- cabal-install/src/Distribution/Client/Init/Types.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cabal-install/src/Distribution/Client/Init/Types.hs b/cabal-install/src/Distribution/Client/Init/Types.hs index 93df5800983..8da7ba2b52b 100644 --- a/cabal-install/src/Distribution/Client/Init/Types.hs +++ b/cabal-install/src/Distribution/Client/Init/Types.hs @@ -441,7 +441,7 @@ instance Interactive PurePrompt where readProcessWithExitCode !_ !_ !_ = do input <- pop return (ExitSuccess, input, "") - maybeReadProcessWithExitCode = Just <$> readProcessWithExitCode + maybeReadProcessWithExitCode a b c = Just <$> readProcessWithExitCode a b c getEnvironment = fmap (map read) popList getCurrentYear = fmap read pop listFilesInside pred' !_ = do From 37977935518569fda5055a08fa2e4be00d12aa44 Mon Sep 17 00:00:00 2001 From: noiioiu Date: Tue, 29 Oct 2024 21:11:38 -0500 Subject: [PATCH 09/15] Add changelog entry --- changelog.d/pr-10486 | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 changelog.d/pr-10486 diff --git a/changelog.d/pr-10486 b/changelog.d/pr-10486 new file mode 100644 index 00000000000..237d2c857b0 --- /dev/null +++ b/changelog.d/pr-10486 @@ -0,0 +1,12 @@ +synopsis: Fix a bug that causes `cabal init` to crash if `git` is not installed +packages: cabal-install +prs: #10486 +issues: #10484 #8478 +significance: + +description: { + +- `cabal init` tries to use `git config` to guess the user's name and email. + It no longer crashes if there is no executable named `git` on $PATH. + +} From 7af962844f56745ec51808ee154b9373ed6ab1c9 Mon Sep 17 00:00:00 2001 From: noiioiu Date: Wed, 30 Oct 2024 23:08:35 -0500 Subject: [PATCH 10/15] Add test for `cabal init` when `git` is not installed --- .../PackageTests/Init/init-without-git.out | 6 +++++ .../Init/init-without-git.test.hs | 27 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 cabal-testsuite/PackageTests/Init/init-without-git.out create mode 100644 cabal-testsuite/PackageTests/Init/init-without-git.test.hs diff --git a/cabal-testsuite/PackageTests/Init/init-without-git.out b/cabal-testsuite/PackageTests/Init/init-without-git.out new file mode 100644 index 00000000000..ea50b9e3107 --- /dev/null +++ b/cabal-testsuite/PackageTests/Init/init-without-git.out @@ -0,0 +1,6 @@ +# cabal init +# Setup configure +Configuring app-0.1.0.0... +# Setup build +Preprocessing executable 'app' for app-0.1.0.0.. +Building executable 'app' for app-0.1.0.0.. diff --git a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs new file mode 100644 index 00000000000..0768ce1a566 --- /dev/null +++ b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs @@ -0,0 +1,27 @@ +import Test.Cabal.Prelude +import System.Directory +import System.FilePath +import Distribution.Simple.Utils +import Distribution.Verbosity + +-- Test cabal init when git is not installed +main = do + tmp <- getTemporaryDirectory + withTempDirectory normal tmp "bin.XXXX" $ + \bin -> cabalTest . withSourceCopyDir "app" $ + do + ghc_path <- programPathM ghcProgram + cabal_path <- programPathM cabalProgram + withSymlink ghc_path (bin "ghc") . withSymlink cabal_path (bin "cabal") . + withEnv [("PATH", Just bin)] . + withSourceCopyDir "app" $ do + cwd <- fmap testSourceCopyDir getTestEnv + + buildOut <- withDirectory cwd $ do + cabalWithStdin "init" ["-i"] + "2\n\n5\n\n\n2\n\n\n\n\n\n\n\n\n\n" + setup "configure" [] + setup' "build" ["app"] + + assertFileDoesContain (cwd "app.cabal") "3.0" + assertOutputContains "Linking" buildOut From 032f5b13ad0aa176bd57d7e59501077b02cf8c61 Mon Sep 17 00:00:00 2001 From: noiioiu Date: Wed, 30 Oct 2024 23:43:33 -0500 Subject: [PATCH 11/15] Remove withSourceCopyDir from test --- .../Init/init-without-git.test.hs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs index 0768ce1a566..3d0c50c5009 100644 --- a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs @@ -13,15 +13,14 @@ main = do ghc_path <- programPathM ghcProgram cabal_path <- programPathM cabalProgram withSymlink ghc_path (bin "ghc") . withSymlink cabal_path (bin "cabal") . - withEnv [("PATH", Just bin)] . - withSourceCopyDir "app" $ do - cwd <- fmap testSourceCopyDir getTestEnv + withEnv [("PATH", Just bin)] $ do + cwd <- fmap testSourceCopyDir getTestEnv - buildOut <- withDirectory cwd $ do - cabalWithStdin "init" ["-i"] - "2\n\n5\n\n\n2\n\n\n\n\n\n\n\n\n\n" - setup "configure" [] - setup' "build" ["app"] + buildOut <- withDirectory cwd $ do + cabalWithStdin "init" ["-i"] + "2\n\n5\n\n\n2\n\n\n\n\n\n\n\n\n\n" + setup "configure" [] + setup' "build" ["app"] - assertFileDoesContain (cwd "app.cabal") "3.0" - assertOutputContains "Linking" buildOut + assertFileDoesContain (cwd "app.cabal") "3.0" + assertOutputContains "Linking" buildOut From 380aa65ea85781fdc36cee9f7bc82872d1ed7afa Mon Sep 17 00:00:00 2001 From: noiioiu Date: Thu, 31 Oct 2024 00:13:50 -0500 Subject: [PATCH 12/15] Remove withSourceCopyDir from test --- cabal-testsuite/PackageTests/Init/init-without-git.test.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs index 3d0c50c5009..87dbea4d51f 100644 --- a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs @@ -8,7 +8,7 @@ import Distribution.Verbosity main = do tmp <- getTemporaryDirectory withTempDirectory normal tmp "bin.XXXX" $ - \bin -> cabalTest . withSourceCopyDir "app" $ + \bin -> cabalTest $ do ghc_path <- programPathM ghcProgram cabal_path <- programPathM cabalProgram From c5e22b913c4fdec19e433eafd74914b93901aaf5 Mon Sep 17 00:00:00 2001 From: noiioiu Date: Thu, 31 Oct 2024 00:57:41 -0500 Subject: [PATCH 13/15] Remove configure and build from test --- cabal-testsuite/PackageTests/Init/init-without-git.out | 5 ----- cabal-testsuite/PackageTests/Init/init-without-git.test.hs | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/cabal-testsuite/PackageTests/Init/init-without-git.out b/cabal-testsuite/PackageTests/Init/init-without-git.out index ea50b9e3107..9a143a9375c 100644 --- a/cabal-testsuite/PackageTests/Init/init-without-git.out +++ b/cabal-testsuite/PackageTests/Init/init-without-git.out @@ -1,6 +1 @@ # cabal init -# Setup configure -Configuring app-0.1.0.0... -# Setup build -Preprocessing executable 'app' for app-0.1.0.0.. -Building executable 'app' for app-0.1.0.0.. diff --git a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs index 87dbea4d51f..d9089687a09 100644 --- a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs @@ -16,11 +16,8 @@ main = do withEnv [("PATH", Just bin)] $ do cwd <- fmap testSourceCopyDir getTestEnv - buildOut <- withDirectory cwd $ do + withDirectory cwd $ do cabalWithStdin "init" ["-i"] "2\n\n5\n\n\n2\n\n\n\n\n\n\n\n\n\n" - setup "configure" [] - setup' "build" ["app"] assertFileDoesContain (cwd "app.cabal") "3.0" - assertOutputContains "Linking" buildOut From 84cdecf86da1f328695ca49f51ff9493b622174b Mon Sep 17 00:00:00 2001 From: noiioiu Date: Thu, 31 Oct 2024 01:36:05 -0500 Subject: [PATCH 14/15] Remove assert --- cabal-testsuite/PackageTests/Init/init-without-git.test.hs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs index d9089687a09..644fa485cc6 100644 --- a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs @@ -7,7 +7,7 @@ import Distribution.Verbosity -- Test cabal init when git is not installed main = do tmp <- getTemporaryDirectory - withTempDirectory normal tmp "bin.XXXX" $ + withTempDirectory normal tmp "bin" $ \bin -> cabalTest $ do ghc_path <- programPathM ghcProgram @@ -16,8 +16,6 @@ main = do withEnv [("PATH", Just bin)] $ do cwd <- fmap testSourceCopyDir getTestEnv - withDirectory cwd $ do + void . withDirectory cwd $ do cabalWithStdin "init" ["-i"] "2\n\n5\n\n\n2\n\n\n\n\n\n\n\n\n\n" - - assertFileDoesContain (cwd "app.cabal") "3.0" From 7f1790425f466b264587a50f7978d4f7485b463f Mon Sep 17 00:00:00 2001 From: noiioiu Date: Thu, 31 Oct 2024 02:37:56 -0500 Subject: [PATCH 15/15] Skip test on windows --- cabal-testsuite/PackageTests/Init/init-without-git.test.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs index 644fa485cc6..4c98f751c57 100644 --- a/cabal-testsuite/PackageTests/Init/init-without-git.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-without-git.test.hs @@ -6,6 +6,7 @@ import Distribution.Verbosity -- Test cabal init when git is not installed main = do + skipIfWindows "Might fail on windows." tmp <- getTemporaryDirectory withTempDirectory normal tmp "bin" $ \bin -> cabalTest $