parent
							
								
									1c2cf98850
								
							
						
					
					
						commit
						3bdc82c99b
					
				@ -1387,8 +1387,8 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
 | 
				
			|||||||
                            exitWith (ExitFailure 2)
 | 
					                            exitWith (ExitFailure 2)
 | 
				
			||||||
                let s' = AppState settings dirs keybindings ghcupInfo pfreq
 | 
					                let s' = AppState settings dirs keybindings ghcupInfo pfreq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                race_ (liftIO $ runLogger $ flip runReaderT dirs $ cleanupGHCupTmp)
 | 
					                race_ (liftIO $ runLogger $ flip runReaderT dirs $ cleanupTrash)
 | 
				
			||||||
                      (threadDelay 5000000 >> runLogger ($(logWarn) [i|Killing cleanup thread (exceeded 5s timeout)... please remove leftover files in #{tmpDir} manually|]))
 | 
					                      (threadDelay 5000000 >> runLogger ($(logWarn) [i|Killing cleanup thread (exceeded 5s timeout)... please remove leftover files in #{recycleDir} manually|]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                lookupEnv "GHCUP_SKIP_UPDATE_CHECK" >>= \case
 | 
					                lookupEnv "GHCUP_SKIP_UPDATE_CHECK" >>= \case
 | 
				
			||||||
                  Nothing -> runLogger $ flip runReaderT s' $ checkForUpdates
 | 
					                  Nothing -> runLogger $ flip runReaderT s' $ checkForUpdates
 | 
				
			||||||
@ -1422,6 +1422,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
 | 
				
			|||||||
          -- Effect interpreters --
 | 
					          -- Effect interpreters --
 | 
				
			||||||
          -------------------------
 | 
					          -------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          let runInstTool' appstate' mInstPlatform =
 | 
					          let runInstTool' appstate' mInstPlatform =
 | 
				
			||||||
                runLogger
 | 
					                runLogger
 | 
				
			||||||
                  . flip runReaderT (maybe appstate' (\x -> appstate'{ pfreq = x } :: AppState) mInstPlatform)
 | 
					                  . flip runReaderT (maybe appstate' (\x -> appstate'{ pfreq = x } :: AppState) mInstPlatform)
 | 
				
			||||||
@ -1519,6 +1520,9 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
 | 
				
			|||||||
          let runRm =
 | 
					          let runRm =
 | 
				
			||||||
                runLogger . runAppState . runE @'[NotInstalled]
 | 
					                runLogger . runAppState . runE @'[NotInstalled]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          let runNuke s' =
 | 
				
			||||||
 | 
					                runLogger . flip runReaderT s' . runE @'[NotInstalled]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          let runDebugInfo =
 | 
					          let runDebugInfo =
 | 
				
			||||||
                runLogger
 | 
					                runLogger
 | 
				
			||||||
                  . runAppState
 | 
					                  . runAppState
 | 
				
			||||||
@ -2067,7 +2071,8 @@ Make sure to clean up #{tmpdir} afterwards.|])
 | 
				
			|||||||
                    )
 | 
					                    )
 | 
				
			||||||
                  pure ExitSuccess
 | 
					                  pure ExitSuccess
 | 
				
			||||||
                Just uri -> do
 | 
					                Just uri -> do
 | 
				
			||||||
                  pfreq <- runAppState getPlatformReq
 | 
					                  s' <- appState
 | 
				
			||||||
 | 
					                  pfreq <- flip runReaderT s' getPlatformReq
 | 
				
			||||||
                  let uri' = T.unpack . decUTF8Safe . serializeURIRef' $ uri
 | 
					                  let uri' = T.unpack . decUTF8Safe . serializeURIRef' $ uri
 | 
				
			||||||
                      cmd = case _rPlatform pfreq of
 | 
					                      cmd = case _rPlatform pfreq of
 | 
				
			||||||
                              Darwin  -> "open"
 | 
					                              Darwin  -> "open"
 | 
				
			||||||
@ -2077,7 +2082,6 @@ Make sure to clean up #{tmpdir} afterwards.|])
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                  if clOpen
 | 
					                  if clOpen
 | 
				
			||||||
                    then do
 | 
					                    then do
 | 
				
			||||||
                      s' <- appState
 | 
					 | 
				
			||||||
                      flip runReaderT s' $
 | 
					                      flip runReaderT s' $
 | 
				
			||||||
                        exec cmd
 | 
					                        exec cmd
 | 
				
			||||||
                             [T.unpack $ decUTF8Safe $ serializeURIRef' uri]
 | 
					                             [T.unpack $ decUTF8Safe $ serializeURIRef' uri]
 | 
				
			||||||
@ -2089,10 +2093,10 @@ Make sure to clean up #{tmpdir} afterwards.|])
 | 
				
			|||||||
                                  >> pure (ExitFailure 13)
 | 
					                                  >> pure (ExitFailure 13)
 | 
				
			||||||
                    else putStrLn uri' >> pure ExitSuccess
 | 
					                    else putStrLn uri' >> pure ExitSuccess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Nuke ->
 | 
					            Nuke -> do
 | 
				
			||||||
              runRm (do
 | 
					              s' <- liftIO appState
 | 
				
			||||||
                   s' <- liftIO appState
 | 
					              void $ liftIO $ evaluate $ force s'
 | 
				
			||||||
                   void $ liftIO $ evaluate $ force s'
 | 
					              runNuke s' (do
 | 
				
			||||||
                   lift $ $logWarn "WARNING: This will remove GHCup and all installed components from your system."
 | 
					                   lift $ $logWarn "WARNING: This will remove GHCup and all installed components from your system."
 | 
				
			||||||
                   lift $ $logWarn "Waiting 10 seconds before commencing, if you want to cancel it, now would be the time."
 | 
					                   lift $ $logWarn "Waiting 10 seconds before commencing, if you want to cancel it, now would be the time."
 | 
				
			||||||
                   liftIO $ threadDelay 10000000  -- wait 10s
 | 
					                   liftIO $ threadDelay 10000000  -- wait 10s
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										100
									
								
								lib/GHCup.hs
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								lib/GHCup.hs
									
									
									
									
									
								
							@ -54,6 +54,9 @@ import           Control.Monad.Logger
 | 
				
			|||||||
import           Control.Monad.Reader
 | 
					import           Control.Monad.Reader
 | 
				
			||||||
import           Control.Monad.Trans.Resource
 | 
					import           Control.Monad.Trans.Resource
 | 
				
			||||||
                                         hiding ( throwM )
 | 
					                                         hiding ( throwM )
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					import           Control.Monad.IO.Unlift        ( MonadUnliftIO( withRunInIO ) )
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
import           Data.ByteString                ( ByteString )
 | 
					import           Data.ByteString                ( ByteString )
 | 
				
			||||||
import           Data.Either
 | 
					import           Data.Either
 | 
				
			||||||
import           Data.List
 | 
					import           Data.List
 | 
				
			||||||
@ -252,22 +255,6 @@ installPackedGHC :: ( MonadMask m
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
                       ] m ()
 | 
					                       ] m ()
 | 
				
			||||||
installPackedGHC dl msubdir inst ver = do
 | 
					installPackedGHC dl msubdir inst ver = do
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					 | 
				
			||||||
  lift $ $(logInfo) "Installing GHC (this may take a while)"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Dirs { tmpDir } <- lift getDirs
 | 
					 | 
				
			||||||
  unpackDir <- liftIO $ emptyTempFile tmpDir "ghc"
 | 
					 | 
				
			||||||
  lift $ rmFile unpackDir
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  liftE $ unpackToDir unpackDir dl
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  d <- case msubdir of
 | 
					 | 
				
			||||||
    Just td -> liftE $ intoSubdir unpackDir td
 | 
					 | 
				
			||||||
    Nothing -> pure unpackDir
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  liftIO $ Win32.moveFileEx d (Just inst) 0
 | 
					 | 
				
			||||||
  lift $ rmPathForcibly unpackDir
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  PlatformRequest {..} <- lift getPlatformReq
 | 
					  PlatformRequest {..} <- lift getPlatformReq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  -- unpack
 | 
					  -- unpack
 | 
				
			||||||
@ -283,7 +270,6 @@ installPackedGHC dl msubdir inst ver = do
 | 
				
			|||||||
  liftE $ runBuildAction tmpUnpack
 | 
					  liftE $ runBuildAction tmpUnpack
 | 
				
			||||||
                         (Just inst)
 | 
					                         (Just inst)
 | 
				
			||||||
                         (installUnpackedGHC workdir inst ver)
 | 
					                         (installUnpackedGHC workdir inst ver)
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Install an unpacked GHC distribution. This only deals with the GHC
 | 
					-- | Install an unpacked GHC distribution. This only deals with the GHC
 | 
				
			||||||
@ -295,13 +281,29 @@ installUnpackedGHC :: ( MonadReader env m
 | 
				
			|||||||
                      , MonadThrow m
 | 
					                      , MonadThrow m
 | 
				
			||||||
                      , MonadLogger m
 | 
					                      , MonadLogger m
 | 
				
			||||||
                      , MonadIO m
 | 
					                      , MonadIO m
 | 
				
			||||||
 | 
					                      , MonadUnliftIO m
 | 
				
			||||||
 | 
					                      , MonadMask m
 | 
				
			||||||
                      )
 | 
					                      )
 | 
				
			||||||
                   => FilePath      -- ^ Path to the unpacked GHC bindist (where the configure script resides)
 | 
					                   => FilePath      -- ^ Path to the unpacked GHC bindist (where the configure script resides)
 | 
				
			||||||
                   -> FilePath      -- ^ Path to install to
 | 
					                   -> FilePath      -- ^ Path to install to
 | 
				
			||||||
                   -> Version       -- ^ The GHC version
 | 
					                   -> Version       -- ^ The GHC version
 | 
				
			||||||
                   -> Excepts '[ProcessError] m ()
 | 
					                   -> Excepts '[ProcessError] m ()
 | 
				
			||||||
installUnpackedGHC path inst ver = do
 | 
					installUnpackedGHC path inst ver = do
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					  lift $ $(logInfo) "Installing GHC (this may take a while)"
 | 
				
			||||||
 | 
					  -- Windows bindists are relocatable and don't need
 | 
				
			||||||
 | 
					  -- to run configure.
 | 
				
			||||||
 | 
					  -- We also must make sure to preserve mtime to not confuse ghc-pkg.
 | 
				
			||||||
 | 
					  lift $ withRunInIO $ \run -> flip onException (run $ recyclePathForcibly inst) $ copyDirectoryRecursive path inst $ \source dest -> do
 | 
				
			||||||
 | 
					    mtime <- getModificationTime source
 | 
				
			||||||
 | 
					    Win32.moveFile source dest
 | 
				
			||||||
 | 
					    setModificationTime dest mtime
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
  PlatformRequest {..} <- lift getPlatformReq
 | 
					  PlatformRequest {..} <- lift getPlatformReq
 | 
				
			||||||
 | 
					  liftIO $ copyDirectoryRecursive path inst $ \source dest -> do
 | 
				
			||||||
 | 
					    mtime <- getModificationTime source
 | 
				
			||||||
 | 
					    copyFile source dest
 | 
				
			||||||
 | 
					    setModificationTime dest mtime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let alpineArgs
 | 
					  let alpineArgs
 | 
				
			||||||
       | ver >= [vver|8.2.2|], Linux Alpine <- _rPlatform
 | 
					       | ver >= [vver|8.2.2|], Linux Alpine <- _rPlatform
 | 
				
			||||||
@ -312,9 +314,6 @@ installUnpackedGHC path inst ver = do
 | 
				
			|||||||
  lift $ $(logInfo) "Installing GHC (this may take a while)"
 | 
					  lift $ $(logInfo) "Installing GHC (this may take a while)"
 | 
				
			||||||
  lEM $ execLogged "sh"
 | 
					  lEM $ execLogged "sh"
 | 
				
			||||||
                   ("./configure" : ("--prefix=" <> inst) 
 | 
					                   ("./configure" : ("--prefix=" <> inst) 
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					 | 
				
			||||||
                    : "--enable-tarballs-autodownload"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                    : alpineArgs
 | 
					                    : alpineArgs
 | 
				
			||||||
                   )
 | 
					                   )
 | 
				
			||||||
                   (Just path)
 | 
					                   (Just path)
 | 
				
			||||||
@ -322,6 +321,7 @@ installUnpackedGHC path inst ver = do
 | 
				
			|||||||
                   Nothing
 | 
					                   Nothing
 | 
				
			||||||
  lEM $ make ["install"] (Just path)
 | 
					  lEM $ make ["install"] (Just path)
 | 
				
			||||||
  pure ()
 | 
					  pure ()
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Installs GHC into @~\/.ghcup\/ghc/\<ver\>@ and places the
 | 
					-- | Installs GHC into @~\/.ghcup\/ghc/\<ver\>@ and places the
 | 
				
			||||||
@ -1310,7 +1310,7 @@ rmGHCVer ver = do
 | 
				
			|||||||
  -- then fix them (e.g. with an earlier version)
 | 
					  -- then fix them (e.g. with an earlier version)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lift $ $(logInfo) [i|Removing directory recursively: #{dir}|]
 | 
					  lift $ $(logInfo) [i|Removing directory recursively: #{dir}|]
 | 
				
			||||||
  lift $ rmPathForcibly dir
 | 
					  lift $ recyclePathForcibly dir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  v' <-
 | 
					  v' <-
 | 
				
			||||||
    handle
 | 
					    handle
 | 
				
			||||||
@ -1322,9 +1322,7 @@ rmGHCVer ver = do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  Dirs {..} <- lift getDirs
 | 
					  Dirs {..} <- lift getDirs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lift
 | 
					  lift $ hideError doesNotExistErrorType $ rmDirectoryLink (baseDir </> "share")
 | 
				
			||||||
    $ hideError doesNotExistErrorType
 | 
					 | 
				
			||||||
    $ rmFile (baseDir </> "share")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Delete a cabal version. Will try to fix the @cabal@ symlink
 | 
					-- | Delete a cabal version. Will try to fix the @cabal@ symlink
 | 
				
			||||||
@ -1349,7 +1347,7 @@ rmCabalVer ver = do
 | 
				
			|||||||
  Dirs {..} <- lift getDirs
 | 
					  Dirs {..} <- lift getDirs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let cabalFile = "cabal-" <> T.unpack (prettyVer ver) <> exeExt
 | 
					  let cabalFile = "cabal-" <> T.unpack (prettyVer ver) <> exeExt
 | 
				
			||||||
  lift $ hideError doesNotExistErrorType $ rmFile (binDir </> cabalFile)
 | 
					  lift $ hideError doesNotExistErrorType $ recycleFile (binDir </> cabalFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  when (Just ver == cSet) $ do
 | 
					  when (Just ver == cSet) $ do
 | 
				
			||||||
    cVers <- lift $ fmap rights getInstalledCabals
 | 
					    cVers <- lift $ fmap rights getInstalledCabals
 | 
				
			||||||
@ -1380,7 +1378,7 @@ rmHLSVer ver = do
 | 
				
			|||||||
  Dirs {..} <- lift getDirs
 | 
					  Dirs {..} <- lift getDirs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bins <- lift $ hlsAllBinaries ver
 | 
					  bins <- lift $ hlsAllBinaries ver
 | 
				
			||||||
  forM_ bins $ \f -> lift $ rmFile (binDir </> f)
 | 
					  forM_ bins $ \f -> lift $ recycleFile (binDir </> f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  when (Just ver == isHlsSet) $ do
 | 
					  when (Just ver == isHlsSet) $ do
 | 
				
			||||||
    -- delete all set symlinks
 | 
					    -- delete all set symlinks
 | 
				
			||||||
@ -1418,7 +1416,7 @@ rmStackVer ver = do
 | 
				
			|||||||
  Dirs {..} <- lift getDirs
 | 
					  Dirs {..} <- lift getDirs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let stackFile = "stack-" <> T.unpack (prettyVer ver) <> exeExt
 | 
					  let stackFile = "stack-" <> T.unpack (prettyVer ver) <> exeExt
 | 
				
			||||||
  lift $ hideError doesNotExistErrorType $ rmFile (binDir </> stackFile)
 | 
					  lift $ hideError doesNotExistErrorType $ recycleFile (binDir </> stackFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  when (Just ver == sSet) $ do
 | 
					  when (Just ver == sSet) $ do
 | 
				
			||||||
    sVers <- lift $ fmap rights getInstalledStacks
 | 
					    sVers <- lift $ fmap rights getInstalledStacks
 | 
				
			||||||
@ -1434,6 +1432,7 @@ rmGhcup :: ( MonadReader env m
 | 
				
			|||||||
           , MonadCatch m
 | 
					           , MonadCatch m
 | 
				
			||||||
           , MonadLogger m
 | 
					           , MonadLogger m
 | 
				
			||||||
           , MonadMask m
 | 
					           , MonadMask m
 | 
				
			||||||
 | 
					           , MonadUnliftIO m
 | 
				
			||||||
           )
 | 
					           )
 | 
				
			||||||
        => m ()
 | 
					        => m ()
 | 
				
			||||||
rmGhcup = do
 | 
					rmGhcup = do
 | 
				
			||||||
@ -1459,12 +1458,12 @@ rmGhcup = do
 | 
				
			|||||||
  unless areEqualPaths $ $logWarn $ nonStandardInstallLocationMsg currentRunningExecPath
 | 
					  unless areEqualPaths $ $logWarn $ nonStandardInstallLocationMsg currentRunningExecPath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  -- since it doesn't seem possible to delete a running exec in windows
 | 
					  -- since it doesn't seem possible to delete a running exe on windows
 | 
				
			||||||
  -- we move it to temp dir, to be deleted at next reboot
 | 
					  -- we move it to temp dir, to be deleted at next reboot
 | 
				
			||||||
  let tempFilepath = tmpDir </> ghcupFilename
 | 
					  tempFilepath <- mkGhcupTmpDir
 | 
				
			||||||
  hideError UnsupportedOperation $
 | 
					  hideError UnsupportedOperation $
 | 
				
			||||||
            liftIO $ hideError NoSuchThing $
 | 
					            liftIO $ hideError NoSuchThing $
 | 
				
			||||||
            Win32.moveFileEx ghcupFilepath (Just tempFilepath) Win32.mOVEFILE_REPLACE_EXISTING
 | 
					            Win32.moveFileEx ghcupFilepath (Just (tempFilepath </> "ghcup")) 0
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  -- delete it.
 | 
					  -- delete it.
 | 
				
			||||||
  hideError doesNotExistErrorType $ rmFile ghcupFilepath
 | 
					  hideError doesNotExistErrorType $ rmFile ghcupFilepath
 | 
				
			||||||
@ -1512,30 +1511,34 @@ rmGhcupDirs = do
 | 
				
			|||||||
    , binDir
 | 
					    , binDir
 | 
				
			||||||
    , logsDir
 | 
					    , logsDir
 | 
				
			||||||
    , cacheDir
 | 
					    , cacheDir
 | 
				
			||||||
    , tmpDir
 | 
					    , recycleDir
 | 
				
			||||||
    } <- getDirs
 | 
					    } <- getDirs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let envFilePath = baseDir </> "env"
 | 
					  let envFilePath = baseDir </> "env"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  confFilePath <- getConfigFilePath
 | 
					  confFilePath <- getConfigFilePath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rmEnvFile  envFilePath
 | 
					  handleRm $ rmEnvFile  envFilePath
 | 
				
			||||||
  rmConfFile confFilePath
 | 
					  handleRm $ rmConfFile confFilePath
 | 
				
			||||||
  rmDir cacheDir
 | 
					  handleRm $ rmDir cacheDir
 | 
				
			||||||
  rmDir logsDir
 | 
					  handleRm $ rmDir logsDir
 | 
				
			||||||
  rmBinDir   binDir
 | 
					  handleRm $ rmBinDir binDir
 | 
				
			||||||
  rmDir tmpDir
 | 
					  handleRm $ rmDir recycleDir
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  rmDir (baseDir </> "msys64")
 | 
					  $logInfo [i|removing #{(baseDir </> "msys64")}|]
 | 
				
			||||||
 | 
					  handleRm $ rmPathForcibly (baseDir </> "msys64")
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  removeEmptyDirsRecursive baseDir
 | 
					  handleRm $ removeEmptyDirsRecursive baseDir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  -- report files in baseDir that are left-over after
 | 
					  -- report files in baseDir that are left-over after
 | 
				
			||||||
  -- the standard location deletions above
 | 
					  -- the standard location deletions above
 | 
				
			||||||
  hideErrorDef [doesNotExistErrorType] [] $ reportRemainingFiles baseDir
 | 
					  hideErrorDef [doesNotExistErrorType] [] $ reportRemainingFiles baseDir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  where
 | 
					  where
 | 
				
			||||||
 | 
					    handleRm :: (MonadCatch m, MonadLogger m)  => m () -> m ()
 | 
				
			||||||
 | 
					    handleRm = handleIO (\e -> $logWarn [i|Part of the cleanup action failed with error: #{displayException e}
 | 
				
			||||||
 | 
					continuing regardless...|])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rmEnvFile :: (MonadLogger m, MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()
 | 
					    rmEnvFile :: (MonadLogger m, MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()
 | 
				
			||||||
    rmEnvFile enFilePath = do
 | 
					    rmEnvFile enFilePath = do
 | 
				
			||||||
@ -1607,7 +1610,7 @@ rmGhcupDirs = do
 | 
				
			|||||||
      hideError UnsatisfiedConstraints $
 | 
					      hideError UnsatisfiedConstraints $
 | 
				
			||||||
      handleIO' InappropriateType
 | 
					      handleIO' InappropriateType
 | 
				
			||||||
            (handleIfSym filepath)
 | 
					            (handleIfSym filepath)
 | 
				
			||||||
            (liftIO $ rmPath filepath)
 | 
					            (liftIO $ rmDirectory filepath)
 | 
				
			||||||
      where
 | 
					      where
 | 
				
			||||||
        handleIfSym fp e = do
 | 
					        handleIfSym fp e = do
 | 
				
			||||||
          isSym <- liftIO $ pathIsSymbolicLink fp
 | 
					          isSym <- liftIO $ pathIsSymbolicLink fp
 | 
				
			||||||
@ -2136,27 +2139,14 @@ upgradeGHCup mtarget force' = do
 | 
				
			|||||||
  let fn = "ghcup" <> exeExt
 | 
					  let fn = "ghcup" <> exeExt
 | 
				
			||||||
  p <- liftE $ download dli tmp (Just fn)
 | 
					  p <- liftE $ download dli tmp (Just fn)
 | 
				
			||||||
  let destDir = takeDirectory destFile
 | 
					  let destDir = takeDirectory destFile
 | 
				
			||||||
      destFile = fromMaybe (binDir </> fn <> exeExt) mtarget
 | 
					      destFile = fromMaybe (binDir </> fn) mtarget
 | 
				
			||||||
  lift $ $(logDebug) [i|mkdir -p #{destDir}|]
 | 
					  lift $ $(logDebug) [i|mkdir -p #{destDir}|]
 | 
				
			||||||
  liftIO $ createDirRecursive' destDir
 | 
					  liftIO $ createDirRecursive' destDir
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					 | 
				
			||||||
  let tempGhcup = tmpDir </> "ghcup.old"
 | 
					 | 
				
			||||||
  lift $ hideError NoSuchThing $ rmFile tempGhcup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  lift $ $(logDebug) [i|mv #{destFile} #{tempGhcup}|]
 | 
					 | 
				
			||||||
  -- NoSuchThing may be raised when we're updating ghcup from
 | 
					 | 
				
			||||||
  -- a non-standard location
 | 
					 | 
				
			||||||
  liftIO $ hideError NoSuchThing $ Win32.moveFileEx destFile (Just tempGhcup) 0
 | 
					 | 
				
			||||||
  lift $ $(logDebug) [i|cp #{p} #{destFile}|]
 | 
					 | 
				
			||||||
  handleIO (throwE . CopyError . show) $ liftIO $ copyFile p
 | 
					 | 
				
			||||||
                                                           destFile
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  lift $ $(logDebug) [i|rm -f #{destFile}|]
 | 
					  lift $ $(logDebug) [i|rm -f #{destFile}|]
 | 
				
			||||||
  lift $ hideError NoSuchThing $ rmFile destFile
 | 
					  lift $ hideError NoSuchThing $ recycleFile destFile
 | 
				
			||||||
  lift $ $(logDebug) [i|cp #{p} #{destFile}|]
 | 
					  lift $ $(logDebug) [i|cp #{p} #{destFile}|]
 | 
				
			||||||
  handleIO (throwE . CopyError . show) $ liftIO $ copyFile p
 | 
					  handleIO (throwE . CopyError . show) $ liftIO $ copyFile p
 | 
				
			||||||
                                                           destFile
 | 
					                                                           destFile
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  lift $ chmod_755 destFile
 | 
					  lift $ chmod_755 destFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  liftIO (isInPath destFile) >>= \b -> unless b $
 | 
					  liftIO (isInPath destFile) >>= \b -> unless b $
 | 
				
			||||||
 | 
				
			|||||||
@ -265,7 +265,7 @@ getBase uri = do
 | 
				
			|||||||
      pure bs
 | 
					      pure bs
 | 
				
			||||||
    dlWithoutMod json_file = do
 | 
					    dlWithoutMod json_file = do
 | 
				
			||||||
      bs <- liftE $ downloadBS uri'
 | 
					      bs <- liftE $ downloadBS uri'
 | 
				
			||||||
      lift $ hideError doesNotExistErrorType $ rmFile json_file
 | 
					      lift $ hideError doesNotExistErrorType $ recycleFile json_file
 | 
				
			||||||
      liftIO $ L.writeFile json_file bs
 | 
					      liftIO $ L.writeFile json_file bs
 | 
				
			||||||
      liftIO $ setModificationTime json_file (posixSecondsToUTCTime (fromIntegral @Int 0))
 | 
					      liftIO $ setModificationTime json_file (posixSecondsToUTCTime (fromIntegral @Int 0))
 | 
				
			||||||
      pure bs
 | 
					      pure bs
 | 
				
			||||||
@ -388,10 +388,10 @@ download dli dest mfn
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    -- download
 | 
					    -- download
 | 
				
			||||||
    flip onException
 | 
					    flip onException
 | 
				
			||||||
         (lift $ hideError doesNotExistErrorType $ rmFile destFile)
 | 
					         (lift $ hideError doesNotExistErrorType $ recycleFile destFile)
 | 
				
			||||||
     $ catchAllE @_ @'[ProcessError, DownloadFailed, UnsupportedScheme]
 | 
					     $ catchAllE @_ @'[ProcessError, DownloadFailed, UnsupportedScheme]
 | 
				
			||||||
          (\e ->
 | 
					          (\e ->
 | 
				
			||||||
            lift (hideError doesNotExistErrorType $ rmFile destFile)
 | 
					            lift (hideError doesNotExistErrorType $ recycleFile destFile)
 | 
				
			||||||
              >> (throwE . DownloadFailed $ e)
 | 
					              >> (throwE . DownloadFailed $ e)
 | 
				
			||||||
          ) $ do
 | 
					          ) $ do
 | 
				
			||||||
              Settings{ downloader, noNetwork } <- lift getSettings
 | 
					              Settings{ downloader, noNetwork } <- lift getSettings
 | 
				
			||||||
 | 
				
			|||||||
@ -384,7 +384,7 @@ data Dirs = Dirs
 | 
				
			|||||||
  , cacheDir :: FilePath
 | 
					  , cacheDir :: FilePath
 | 
				
			||||||
  , logsDir  :: FilePath
 | 
					  , logsDir  :: FilePath
 | 
				
			||||||
  , confDir  :: FilePath
 | 
					  , confDir  :: FilePath
 | 
				
			||||||
  , tmpDir   :: FilePath
 | 
					  , recycleDir :: FilePath -- mainly used on windows
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  deriving (Show, GHC.Generic)
 | 
					  deriving (Show, GHC.Generic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -53,6 +53,7 @@ import           Control.Monad.Logger
 | 
				
			|||||||
import           Control.Monad.Reader
 | 
					import           Control.Monad.Reader
 | 
				
			||||||
import           Control.Monad.Trans.Resource
 | 
					import           Control.Monad.Trans.Resource
 | 
				
			||||||
                                         hiding ( throwM )
 | 
					                                         hiding ( throwM )
 | 
				
			||||||
 | 
					import           Control.Monad.IO.Unlift        ( MonadUnliftIO( withRunInIO ) )
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
import           Data.Bits
 | 
					import           Data.Bits
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -886,8 +887,17 @@ getChangeLog dls tool (Right tag) =
 | 
				
			|||||||
--
 | 
					--
 | 
				
			||||||
--   1. the build directory, depending on the KeepDirs setting
 | 
					--   1. the build directory, depending on the KeepDirs setting
 | 
				
			||||||
--   2. the install destination, depending on whether the build failed
 | 
					--   2. the install destination, depending on whether the build failed
 | 
				
			||||||
runBuildAction :: (Pretty (V e), Show (V e), MonadReader env m, HasDirs env, HasSettings env, MonadIO m, MonadMask m)
 | 
					runBuildAction :: ( Pretty (V e)
 | 
				
			||||||
               => FilePath          -- ^ build directory (cleaned up depending on Settings)
 | 
					                  , Show (V e)
 | 
				
			||||||
 | 
					                  , MonadReader env m
 | 
				
			||||||
 | 
					                  , HasDirs env
 | 
				
			||||||
 | 
					                  , HasSettings env
 | 
				
			||||||
 | 
					                  , MonadIO m
 | 
				
			||||||
 | 
					                  , MonadMask m
 | 
				
			||||||
 | 
					                  , MonadLogger m
 | 
				
			||||||
 | 
					                  , MonadUnliftIO m
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
 | 
					               => FilePath        -- ^ build directory (cleaned up depending on Settings)
 | 
				
			||||||
               -> Maybe FilePath  -- ^ dir to *always* clean up on exception
 | 
					               -> Maybe FilePath  -- ^ dir to *always* clean up on exception
 | 
				
			||||||
               -> Excepts e m a
 | 
					               -> Excepts e m a
 | 
				
			||||||
               -> Excepts '[BuildFailed] m a
 | 
					               -> Excepts '[BuildFailed] m a
 | 
				
			||||||
@ -895,11 +905,9 @@ runBuildAction bdir instdir action = do
 | 
				
			|||||||
  Settings {..} <- lift getSettings
 | 
					  Settings {..} <- lift getSettings
 | 
				
			||||||
  let exAction = do
 | 
					  let exAction = do
 | 
				
			||||||
        forM_ instdir $ \dir ->
 | 
					        forM_ instdir $ \dir ->
 | 
				
			||||||
          lift $ hideError doesNotExistErrorType $ rmPathForcibly dir
 | 
					          lift $ hideError doesNotExistErrorType $ recyclePathForcibly dir
 | 
				
			||||||
        when (keepDirs == Never)
 | 
					        when (keepDirs == Never)
 | 
				
			||||||
          $ lift
 | 
					          $ lift $ rmBDir bdir
 | 
				
			||||||
          $ hideError doesNotExistErrorType
 | 
					 | 
				
			||||||
          $ rmPathForcibly bdir
 | 
					 | 
				
			||||||
  v <-
 | 
					  v <-
 | 
				
			||||||
    flip onException exAction
 | 
					    flip onException exAction
 | 
				
			||||||
    $ catchAllE
 | 
					    $ catchAllE
 | 
				
			||||||
@ -908,10 +916,20 @@ runBuildAction bdir instdir action = do
 | 
				
			|||||||
          throwE (BuildFailed bdir es)
 | 
					          throwE (BuildFailed bdir es)
 | 
				
			||||||
        ) action
 | 
					        ) action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  when (keepDirs == Never || keepDirs == Errors) $ lift $ rmPathForcibly bdir
 | 
					  when (keepDirs == Never || keepDirs == Errors) $ lift $ rmBDir bdir
 | 
				
			||||||
  pure v
 | 
					  pure v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- | Remove a build directory, ignoring if it doesn't exist and gracefully
 | 
				
			||||||
 | 
					-- printing other errors without crashing.
 | 
				
			||||||
 | 
					rmBDir :: (MonadLogger m, MonadUnliftIO m, MonadIO m) => FilePath -> m ()
 | 
				
			||||||
 | 
					rmBDir dir = withRunInIO (\run -> run $
 | 
				
			||||||
 | 
					           liftIO $ handleIO (\e -> run $ $(logWarn)
 | 
				
			||||||
 | 
					               [i|Couldn't remove build dir #{dir}, error was: #{displayException e}|])
 | 
				
			||||||
 | 
					           $ hideError doesNotExistErrorType
 | 
				
			||||||
 | 
					           $ rmPathForcibly dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
getVersionInfo :: Version
 | 
					getVersionInfo :: Version
 | 
				
			||||||
               -> Tool
 | 
					               -> Tool
 | 
				
			||||||
               -> GHCupDownloads
 | 
					               -> GHCupDownloads
 | 
				
			||||||
@ -1001,10 +1019,10 @@ pathIsLink = pathIsSymbolicLink
 | 
				
			|||||||
rmLink :: (MonadReader env m, HasDirs env, MonadIO m, MonadMask m) => FilePath -> m ()
 | 
					rmLink :: (MonadReader env m, HasDirs env, MonadIO m, MonadMask m) => FilePath -> m ()
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
rmLink fp = do
 | 
					rmLink fp = do
 | 
				
			||||||
  hideError doesNotExistErrorType . rmFile $ fp
 | 
					  hideError doesNotExistErrorType . recycleFile $ fp
 | 
				
			||||||
  hideError doesNotExistErrorType . rmFile $ (dropExtension fp <.> "shim")
 | 
					  hideError doesNotExistErrorType . recycleFile $ (dropExtension fp <.> "shim")
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
rmLink = hideError doesNotExistErrorType . rmFile
 | 
					rmLink = hideError doesNotExistErrorType . recycleFile
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1049,7 +1067,7 @@ createLink link exe = do
 | 
				
			|||||||
  liftIO $ writeFile shim shimContents
 | 
					  liftIO $ writeFile shim shimContents
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  $(logDebug) [i|rm -f #{exe}|]
 | 
					  $(logDebug) [i|rm -f #{exe}|]
 | 
				
			||||||
  hideError doesNotExistErrorType $ rmFile exe
 | 
					  hideError doesNotExistErrorType $ recycleFile exe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $(logDebug) [i|ln -s #{link} #{exe}|]
 | 
					  $(logDebug) [i|ln -s #{link} #{exe}|]
 | 
				
			||||||
  liftIO $ createFileLink link exe
 | 
					  liftIO $ createFileLink link exe
 | 
				
			||||||
@ -1078,7 +1096,7 @@ ensureGlobalTools = do
 | 
				
			|||||||
  void $ (\(DigestError _ _) -> do
 | 
					  void $ (\(DigestError _ _) -> do
 | 
				
			||||||
      lift $ $(logWarn) [i|Digest doesn't match, redownloading gs.exe...|]
 | 
					      lift $ $(logWarn) [i|Digest doesn't match, redownloading gs.exe...|]
 | 
				
			||||||
      lift $ $(logDebug) [i|rm -f #{shimDownload}|]
 | 
					      lift $ $(logDebug) [i|rm -f #{shimDownload}|]
 | 
				
			||||||
      lift $ hideError doesNotExistErrorType $ rmFile (cacheDir dirs </> "gs.exe")
 | 
					      lift $ hideError doesNotExistErrorType $ recycleFile (cacheDir dirs </> "gs.exe")
 | 
				
			||||||
      liftE @'[DigestError , DownloadFailed] $ dl
 | 
					      liftE @'[DigestError , DownloadFailed] $ dl
 | 
				
			||||||
    ) `catchE` (liftE @'[DigestError , DownloadFailed] dl)
 | 
					    ) `catchE` (liftE @'[DigestError , DownloadFailed] dl)
 | 
				
			||||||
  pure ()
 | 
					  pure ()
 | 
				
			||||||
@ -1089,14 +1107,14 @@ ensureGlobalTools = do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
-- | Ensure ghcup directory structure exists.
 | 
					-- | Ensure ghcup directory structure exists.
 | 
				
			||||||
ensureDirectories :: Dirs -> IO ()
 | 
					ensureDirectories :: Dirs -> IO ()
 | 
				
			||||||
ensureDirectories (Dirs baseDir binDir cacheDir logsDir confDir tmpDir) = do
 | 
					ensureDirectories (Dirs baseDir binDir cacheDir logsDir confDir trashDir) = do
 | 
				
			||||||
  createDirRecursive' baseDir
 | 
					  createDirRecursive' baseDir
 | 
				
			||||||
  createDirRecursive' (baseDir </> "ghc")
 | 
					  createDirRecursive' (baseDir </> "ghc")
 | 
				
			||||||
  createDirRecursive' binDir
 | 
					  createDirRecursive' binDir
 | 
				
			||||||
  createDirRecursive' cacheDir
 | 
					  createDirRecursive' cacheDir
 | 
				
			||||||
  createDirRecursive' logsDir
 | 
					  createDirRecursive' logsDir
 | 
				
			||||||
  createDirRecursive' confDir
 | 
					  createDirRecursive' confDir
 | 
				
			||||||
  createDirRecursive' tmpDir
 | 
					  createDirRecursive' trashDir
 | 
				
			||||||
  pure ()
 | 
					  pure ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1110,4 +1128,3 @@ ensureDirectories (Dirs baseDir binDir cacheDir logsDir confDir tmpDir) = do
 | 
				
			|||||||
ghcBinaryName :: GHCTargetVersion -> String
 | 
					ghcBinaryName :: GHCTargetVersion -> String
 | 
				
			||||||
ghcBinaryName (GHCTargetVersion (Just t) v') = T.unpack (t <> "-ghc-" <> prettyVer v' <> T.pack exeExt)
 | 
					ghcBinaryName (GHCTargetVersion (Just t) v') = T.unpack (t <> "-ghc-" <> prettyVer v' <> T.pack exeExt)
 | 
				
			||||||
ghcBinaryName (GHCTargetVersion Nothing  v') = T.unpack ("ghc-" <> prettyVer v' <> T.pack exeExt)
 | 
					ghcBinaryName (GHCTargetVersion Nothing  v') = T.unpack ("ghc-" <> prettyVer v' <> T.pack exeExt)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,7 @@ module GHCup.Utils.Dirs
 | 
				
			|||||||
#if !defined(IS_WINDOWS)
 | 
					#if !defined(IS_WINDOWS)
 | 
				
			||||||
  , useXDG
 | 
					  , useXDG
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  , cleanupGHCupTmp
 | 
					  , cleanupTrash
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -190,23 +190,21 @@ ghcupLogsDir = do
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Defaults to '~/.ghcup/tmp.
 | 
					-- | '~/.ghcup/trash'.
 | 
				
			||||||
--
 | 
					-- Mainly used on windows to improve file removal operations
 | 
				
			||||||
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
 | 
					ghcupRecycleDir :: IO FilePath
 | 
				
			||||||
-- then uses 'XDG_DATA_HOME/ghcup/tmp' as per xdg spec.
 | 
					ghcupRecycleDir = ghcupBaseDir <&> (</> "trash")
 | 
				
			||||||
ghcupTmpDir :: IO FilePath
 | 
					 | 
				
			||||||
ghcupTmpDir = ghcupBaseDir <&> (</> "tmp")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
getAllDirs :: IO Dirs
 | 
					getAllDirs :: IO Dirs
 | 
				
			||||||
getAllDirs = do
 | 
					getAllDirs = do
 | 
				
			||||||
  baseDir  <- ghcupBaseDir
 | 
					  baseDir    <- ghcupBaseDir
 | 
				
			||||||
  binDir   <- ghcupBinDir
 | 
					  binDir     <- ghcupBinDir
 | 
				
			||||||
  cacheDir <- ghcupCacheDir
 | 
					  cacheDir   <- ghcupCacheDir
 | 
				
			||||||
  logsDir  <- ghcupLogsDir
 | 
					  logsDir    <- ghcupLogsDir
 | 
				
			||||||
  confDir  <- ghcupConfigDir
 | 
					  confDir    <- ghcupConfigDir
 | 
				
			||||||
  tmpDir   <- ghcupTmpDir
 | 
					  recycleDir <- ghcupRecycleDir
 | 
				
			||||||
  pure Dirs { .. }
 | 
					  pure Dirs { .. }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -271,10 +269,6 @@ mkGhcupTmpDir :: ( MonadReader env m
 | 
				
			|||||||
                 , MonadIO m)
 | 
					                 , MonadIO m)
 | 
				
			||||||
              => m FilePath
 | 
					              => m FilePath
 | 
				
			||||||
mkGhcupTmpDir = do
 | 
					mkGhcupTmpDir = do
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					 | 
				
			||||||
  Dirs { tmpDir } <- getDirs
 | 
					 | 
				
			||||||
  liftIO $ createTempDirectory tmpDir "ghcup"
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  tmpdir <- liftIO getCanonicalTemporaryDirectory
 | 
					  tmpdir <- liftIO getCanonicalTemporaryDirectory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let minSpace = 5000 -- a rough guess, aight?
 | 
					  let minSpace = 5000 -- a rough guess, aight?
 | 
				
			||||||
@ -292,7 +286,6 @@ mkGhcupTmpDir = do
 | 
				
			|||||||
  truncate' :: Double -> Int -> Double
 | 
					  truncate' :: Double -> Int -> Double
 | 
				
			||||||
  truncate' x n = fromIntegral (floor (x * t) :: Integer) / t
 | 
					  truncate' x n = fromIntegral (floor (x * t) :: Integer) / t
 | 
				
			||||||
      where t = 10^n
 | 
					      where t = 10^n
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
withGHCupTmpDir :: ( MonadReader env m
 | 
					withGHCupTmpDir :: ( MonadReader env m
 | 
				
			||||||
@ -305,7 +298,15 @@ withGHCupTmpDir :: ( MonadReader env m
 | 
				
			|||||||
                   , MonadMask m
 | 
					                   , MonadMask m
 | 
				
			||||||
                   , MonadIO m)
 | 
					                   , MonadIO m)
 | 
				
			||||||
                => m FilePath
 | 
					                => m FilePath
 | 
				
			||||||
withGHCupTmpDir = snd <$> withRunInIO (\run -> run $ allocate (run mkGhcupTmpDir) (run . rmPathForcibly))
 | 
					withGHCupTmpDir = snd <$> withRunInIO (\run ->
 | 
				
			||||||
 | 
					  run
 | 
				
			||||||
 | 
					    $ allocate
 | 
				
			||||||
 | 
					        (run mkGhcupTmpDir)
 | 
				
			||||||
 | 
					        (\fp ->
 | 
				
			||||||
 | 
					            handleIO (\e -> run
 | 
				
			||||||
 | 
					                $ $(logDebug) [i|Resource cleanup failed for "#{fp}", error was: #{displayException e}|])
 | 
				
			||||||
 | 
					            . rmPathForcibly
 | 
				
			||||||
 | 
					            $ fp))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -333,18 +334,21 @@ relativeSymlink p1 p2 =
 | 
				
			|||||||
        <> joinPath ([pathSeparator] : drop (length common) d2)
 | 
					        <> joinPath ([pathSeparator] : drop (length common) d2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cleanupGHCupTmp :: ( MonadIO m
 | 
					cleanupTrash :: ( MonadIO m
 | 
				
			||||||
                   , MonadMask m
 | 
					                , MonadMask m
 | 
				
			||||||
                   , MonadLogger m
 | 
					                , MonadLogger m
 | 
				
			||||||
                   , MonadReader env m
 | 
					                , MonadReader env m
 | 
				
			||||||
                   , HasDirs env
 | 
					                , HasDirs env
 | 
				
			||||||
                   )
 | 
					                )
 | 
				
			||||||
                => m ()
 | 
					             => m ()
 | 
				
			||||||
cleanupGHCupTmp = do
 | 
					cleanupTrash = do
 | 
				
			||||||
  Dirs { tmpDir } <- getDirs
 | 
					  Dirs { recycleDir } <- getDirs
 | 
				
			||||||
  contents <- liftIO $ listDirectory tmpDir
 | 
					  contents <- liftIO $ listDirectory recycleDir
 | 
				
			||||||
  if null contents
 | 
					  if null contents
 | 
				
			||||||
  then pure ()
 | 
					  then pure ()
 | 
				
			||||||
  else do
 | 
					  else do
 | 
				
			||||||
    $(logWarn) [i|Removing leftover files in #{tmpDir}|]
 | 
					    $(logWarn) [i|Removing leftover files in #{recycleDir}|]
 | 
				
			||||||
    forM_ contents (\fp -> liftIO $ removePathForcibly (tmpDir </> fp))
 | 
					    forM_ contents (\fp -> handleIO (\e ->
 | 
				
			||||||
 | 
					        $(logDebug) [i|Resource cleanup failed for "#{fp}", error was: #{displayException e}|]
 | 
				
			||||||
 | 
					      ) $ liftIO $ removePathForcibly (recycleDir </> fp))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -97,7 +97,7 @@ initGHCupFileLogging = do
 | 
				
			|||||||
                   execBlank
 | 
					                   execBlank
 | 
				
			||||||
                   ([s|^.*\.log$|] :: B.ByteString)
 | 
					                   ([s|^.*\.log$|] :: B.ByteString)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  forM_ logFiles $ hideError doesNotExistErrorType . rmFile . (logsDir </>)
 | 
					  forM_ logFiles $ hideError doesNotExistErrorType . recycleFile . (logsDir </>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  liftIO $ writeFile logfile ""
 | 
					  liftIO $ writeFile logfile ""
 | 
				
			||||||
  pure logfile
 | 
					  pure logfile
 | 
				
			||||||
 | 
				
			|||||||
@ -323,17 +323,16 @@ createDirRecursive' p =
 | 
				
			|||||||
-- | Recursively copy the contents of one directory to another path.
 | 
					-- | Recursively copy the contents of one directory to another path.
 | 
				
			||||||
--
 | 
					--
 | 
				
			||||||
-- This is a rip-off of Cabal library.
 | 
					-- This is a rip-off of Cabal library.
 | 
				
			||||||
copyDirectoryRecursive :: FilePath -> FilePath -> IO ()
 | 
					copyDirectoryRecursive :: FilePath -> FilePath -> (FilePath -> FilePath -> IO ()) -> IO ()
 | 
				
			||||||
copyDirectoryRecursive srcDir destDir = do
 | 
					copyDirectoryRecursive srcDir destDir doCopy = do
 | 
				
			||||||
  srcFiles <- getDirectoryContentsRecursive srcDir
 | 
					  srcFiles <- getDirectoryContentsRecursive srcDir
 | 
				
			||||||
  copyFilesWith copyFile destDir [ (srcDir, f)
 | 
					  copyFilesWith destDir [ (srcDir, f)
 | 
				
			||||||
                                   | f <- srcFiles ]
 | 
					                          | f <- srcFiles ]
 | 
				
			||||||
  where
 | 
					  where
 | 
				
			||||||
    -- | Common implementation of 'copyFiles', 'installOrdinaryFiles',
 | 
					    -- | Common implementation of 'copyFiles', 'installOrdinaryFiles',
 | 
				
			||||||
    -- 'installExecutableFiles' and 'installMaybeExecutableFiles'.
 | 
					    -- 'installExecutableFiles' and 'installMaybeExecutableFiles'.
 | 
				
			||||||
    copyFilesWith :: (FilePath -> FilePath -> IO ())
 | 
					    copyFilesWith :: FilePath -> [(FilePath, FilePath)] -> IO ()
 | 
				
			||||||
                  -> FilePath -> [(FilePath, FilePath)] -> IO ()
 | 
					    copyFilesWith targetDir srcFiles = do
 | 
				
			||||||
    copyFilesWith doCopy targetDir srcFiles = do
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      -- Create parent directories for everything
 | 
					      -- Create parent directories for everything
 | 
				
			||||||
      let dirs = map (targetDir </>) . nub . map (takeDirectory . snd) $ srcFiles
 | 
					      let dirs = map (targetDir </>) . nub . map (takeDirectory . snd) $ srcFiles
 | 
				
			||||||
@ -378,37 +377,54 @@ getDirectoryContentsRecursive topdir = recurseDirectories [""]
 | 
				
			|||||||
        ignore ['.', '.'] = True
 | 
					        ignore ['.', '.'] = True
 | 
				
			||||||
        ignore _          = False
 | 
					        ignore _          = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- https://github.com/haskell/directory/issues/110
 | 
					-- https://github.com/haskell/directory/issues/110
 | 
				
			||||||
-- https://github.com/haskell/directory/issues/96
 | 
					-- https://github.com/haskell/directory/issues/96
 | 
				
			||||||
-- https://www.sqlite.org/src/info/89f1848d7f
 | 
					-- https://www.sqlite.org/src/info/89f1848d7f
 | 
				
			||||||
rmPathForcibly :: (MonadIO m
 | 
					recyclePathForcibly :: ( MonadIO m
 | 
				
			||||||
                  , MonadReader env m
 | 
					                       , MonadReader env m
 | 
				
			||||||
                  , HasDirs env
 | 
					                       , HasDirs env
 | 
				
			||||||
 | 
					                       , MonadMask m
 | 
				
			||||||
 | 
					                       )
 | 
				
			||||||
 | 
					                    => FilePath
 | 
				
			||||||
 | 
					                    -> m ()
 | 
				
			||||||
 | 
					recyclePathForcibly fp = do
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					  Dirs { recycleDir } <- getDirs
 | 
				
			||||||
 | 
					  tmp <- liftIO $ createTempDirectory recycleDir "recyclePathForcibly"
 | 
				
			||||||
 | 
					  let dest = tmp </> takeFileName fp
 | 
				
			||||||
 | 
					  liftIO (Win32.moveFileEx fp (Just dest) 0)
 | 
				
			||||||
 | 
					      `catch`
 | 
				
			||||||
 | 
					      (\e -> if isPermissionError e {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e)
 | 
				
			||||||
 | 
					      `finally`
 | 
				
			||||||
 | 
					        (liftIO $ handleIO (\_ -> pure ()) $ removePathForcibly tmp)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  liftIO $ removePathForcibly fp
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rmPathForcibly :: ( MonadIO m
 | 
				
			||||||
                  , MonadMask m
 | 
					                  , MonadMask m
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
               => FilePath
 | 
					               => FilePath
 | 
				
			||||||
               -> m ()
 | 
					               -> m ()
 | 
				
			||||||
rmPathForcibly fp = do
 | 
					rmPathForcibly fp =
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  Dirs { tmpDir } <- getDirs
 | 
					  recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
				
			||||||
  tmp <- liftIO $ createTempDirectory tmpDir "rmPathForcibly"
 | 
					    [\_ -> Handler (\e -> pure $ isPermissionError e)
 | 
				
			||||||
  let dest = tmp </> takeFileName fp
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
 | 
				
			||||||
  liftIO (Win32.moveFileEx fp (Just dest) 0)
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
 | 
				
			||||||
      `finally`
 | 
					    ]
 | 
				
			||||||
        recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
					    (\_ -> liftIO $ removePathForcibly fp)
 | 
				
			||||||
          [\_ -> Handler (\e -> pure $ isPermissionError e)
 | 
					 | 
				
			||||||
          ,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
 | 
					 | 
				
			||||||
          ,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
          (\_ -> liftIO $ removePathForcibly tmp)
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  liftIO $ removeDirectoryRecursive fp
 | 
					  liftIO $ removePathForcibly fp
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rmPath :: (MonadIO m, MonadMask m)
 | 
					
 | 
				
			||||||
       => FilePath
 | 
					rmDirectory :: (MonadIO m, MonadMask m)
 | 
				
			||||||
       -> m ()
 | 
					            => FilePath
 | 
				
			||||||
rmPath fp =
 | 
					            -> m ()
 | 
				
			||||||
 | 
					rmDirectory fp =
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
					  recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
				
			||||||
    [\_ -> Handler (\e -> pure $ isPermissionError e)
 | 
					    [\_ -> Handler (\e -> pure $ isPermissionError e)
 | 
				
			||||||
@ -423,27 +439,42 @@ rmPath fp =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
-- https://www.sqlite.org/src/info/89f1848d7f
 | 
					-- https://www.sqlite.org/src/info/89f1848d7f
 | 
				
			||||||
-- https://github.com/haskell/directory/issues/96
 | 
					-- https://github.com/haskell/directory/issues/96
 | 
				
			||||||
 | 
					recycleFile :: ( MonadIO m
 | 
				
			||||||
 | 
					               , MonadMask m
 | 
				
			||||||
 | 
					               , MonadReader env m
 | 
				
			||||||
 | 
					               , HasDirs env
 | 
				
			||||||
 | 
					               )
 | 
				
			||||||
 | 
					            => FilePath
 | 
				
			||||||
 | 
					            -> m ()
 | 
				
			||||||
 | 
					recycleFile fp = do
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					  Dirs { recycleDir } <- getDirs
 | 
				
			||||||
 | 
					  liftIO $ whenM (doesDirectoryExist fp) $ ioError (IOError Nothing InappropriateType "recycleFile" "" Nothing (Just fp))
 | 
				
			||||||
 | 
					  tmp <- liftIO $ createTempDirectory recycleDir "recycleFile"
 | 
				
			||||||
 | 
					  let dest = tmp </> takeFileName fp
 | 
				
			||||||
 | 
					  liftIO (Win32.moveFileEx fp (Just dest) 0)
 | 
				
			||||||
 | 
					    `catch`
 | 
				
			||||||
 | 
					      (\e -> if isPermissionError e {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e)
 | 
				
			||||||
 | 
					    `finally`
 | 
				
			||||||
 | 
					      (liftIO $ handleIO (\_ -> pure ()) $ removePathForcibly tmp)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  liftIO $ removeFile fp
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rmFile :: ( MonadIO m
 | 
					rmFile :: ( MonadIO m
 | 
				
			||||||
          , MonadMask m
 | 
					          , MonadMask m
 | 
				
			||||||
          , MonadReader env m
 | 
					 | 
				
			||||||
          , HasDirs env
 | 
					 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
      => FilePath
 | 
					      => FilePath
 | 
				
			||||||
      -> m ()
 | 
					      -> m ()
 | 
				
			||||||
rmFile fp = do
 | 
					rmFile fp =
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  Dirs { tmpDir } <- getDirs
 | 
					  recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
				
			||||||
  liftIO $ whenM (doesDirectoryExist fp) $ ioError (IOError Nothing InappropriateType "rmFile" "" Nothing (Just fp))
 | 
					    [\_ -> Handler (\e -> pure $ isPermissionError e)
 | 
				
			||||||
  tmp <- liftIO $ createTempDirectory tmpDir "rmFile"
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
 | 
				
			||||||
  let dest = tmp </> takeFileName fp
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
 | 
				
			||||||
  liftIO (Win32.moveFileEx fp (Just dest) 0)
 | 
					    ]
 | 
				
			||||||
    `finally`
 | 
					    (\_ -> liftIO $ removeFile fp)
 | 
				
			||||||
      recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
					 | 
				
			||||||
        [\_ -> Handler (\e -> pure $ isPermissionError e)
 | 
					 | 
				
			||||||
        ,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
 | 
					 | 
				
			||||||
        ,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
        (\_ -> liftIO $ removePathForcibly tmp)
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  liftIO $ removeFile fp
 | 
					  liftIO $ removeFile fp
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -454,9 +485,26 @@ rmDirectoryLink :: (MonadIO m, MonadMask m, MonadReader env m, HasDirs env)
 | 
				
			|||||||
                -> m ()
 | 
					                -> m ()
 | 
				
			||||||
rmDirectoryLink fp = 
 | 
					rmDirectoryLink fp = 
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  rmPathForcibly fp
 | 
					  recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
				
			||||||
 | 
					    [\_ -> Handler (\e -> pure $ isPermissionError e)
 | 
				
			||||||
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
 | 
				
			||||||
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    (\_ -> liftIO $ removeDirectoryLink fp)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  liftIO $ removeFile fp
 | 
					  liftIO $ removeDirectoryLink fp
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					recover :: (MonadIO m, MonadMask m) => m a -> m a
 | 
				
			||||||
 | 
					recover action = 
 | 
				
			||||||
 | 
					  recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
				
			||||||
 | 
					    [\_ -> Handler (\e -> pure $ isPermissionError e)
 | 
				
			||||||
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
 | 
				
			||||||
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    (\_ -> action)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user