Fix file/dir removal on windows, fixes #165
This commit is contained in:
		
							parent
							
								
									b35dbca22e
								
							
						
					
					
						commit
						1c2cf98850
					
				@ -34,6 +34,7 @@ import           GHCup.Version
 | 
				
			|||||||
import           Codec.Archive
 | 
					import           Codec.Archive
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
import           Control.Concurrent
 | 
					import           Control.Concurrent
 | 
				
			||||||
 | 
					import           Control.Concurrent.Async
 | 
				
			||||||
import           Control.DeepSeq                ( force )
 | 
					import           Control.DeepSeq                ( force )
 | 
				
			||||||
import           Control.Exception              ( evaluate )
 | 
					import           Control.Exception              ( evaluate )
 | 
				
			||||||
import           Control.Exception.Safe
 | 
					import           Control.Exception.Safe
 | 
				
			||||||
@ -1342,7 +1343,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
 | 
				
			|||||||
          (settings, keybindings) <- toSettings opt
 | 
					          (settings, keybindings) <- toSettings opt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          -- logger interpreter
 | 
					          -- logger interpreter
 | 
				
			||||||
          logfile <- initGHCupFileLogging logsDir
 | 
					          logfile <- flip runReaderT dirs $ initGHCupFileLogging
 | 
				
			||||||
          let loggerConfig = LoggerConfig
 | 
					          let loggerConfig = LoggerConfig
 | 
				
			||||||
                { lcPrintDebug = verbose settings
 | 
					                { lcPrintDebug = verbose settings
 | 
				
			||||||
                , colorOutter  = B.hPut stderr
 | 
					                , colorOutter  = B.hPut stderr
 | 
				
			||||||
@ -1386,6 +1387,9 @@ 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)
 | 
				
			||||||
 | 
					                      (threadDelay 5000000 >> runLogger ($(logWarn) [i|Killing cleanup thread (exceeded 5s timeout)... please remove leftover files in #{tmpDir} 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
 | 
				
			||||||
                  Just _ -> pure ()
 | 
					                  Just _ -> pure ()
 | 
				
			||||||
 | 
				
			|||||||
@ -202,6 +202,7 @@ executable ghcup
 | 
				
			|||||||
    -fwarn-incomplete-record-updates -threaded
 | 
					    -fwarn-incomplete-record-updates -threaded
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  build-depends:
 | 
					  build-depends:
 | 
				
			||||||
 | 
					    , async                 ^>=2.2.3
 | 
				
			||||||
    , base                  >=4.13     && <5
 | 
					    , base                  >=4.13     && <5
 | 
				
			||||||
    , bytestring            ^>=0.10
 | 
					    , bytestring            ^>=0.10
 | 
				
			||||||
    , containers            ^>=0.6
 | 
					    , containers            ^>=0.6
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										71
									
								
								lib/GHCup.hs
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								lib/GHCup.hs
									
									
									
									
									
								
							@ -257,7 +257,7 @@ installPackedGHC dl msubdir inst ver = do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  Dirs { tmpDir } <- lift getDirs
 | 
					  Dirs { tmpDir } <- lift getDirs
 | 
				
			||||||
  unpackDir <- liftIO $ emptyTempFile tmpDir "ghc"
 | 
					  unpackDir <- liftIO $ emptyTempFile tmpDir "ghc"
 | 
				
			||||||
  liftIO $ rmFile unpackDir
 | 
					  lift $ rmFile unpackDir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  liftE $ unpackToDir unpackDir dl
 | 
					  liftE $ unpackToDir unpackDir dl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -266,7 +266,7 @@ installPackedGHC dl msubdir inst ver = do
 | 
				
			|||||||
    Nothing -> pure unpackDir
 | 
					    Nothing -> pure unpackDir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  liftIO $ Win32.moveFileEx d (Just inst) 0
 | 
					  liftIO $ Win32.moveFileEx d (Just inst) 0
 | 
				
			||||||
  liftIO $ rmPath unpackDir
 | 
					  lift $ rmPathForcibly unpackDir
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  PlatformRequest {..} <- lift getPlatformReq
 | 
					  PlatformRequest {..} <- lift getPlatformReq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -801,7 +801,10 @@ setGHC ver sghc = do
 | 
				
			|||||||
  symlinkShareDir :: ( MonadReader env m
 | 
					  symlinkShareDir :: ( MonadReader env m
 | 
				
			||||||
                     , HasDirs env
 | 
					                     , HasDirs env
 | 
				
			||||||
                     , MonadIO m
 | 
					                     , MonadIO m
 | 
				
			||||||
                     , MonadLogger m)
 | 
					                     , MonadLogger m
 | 
				
			||||||
 | 
					                     , MonadCatch m
 | 
				
			||||||
 | 
					                     , MonadMask m
 | 
				
			||||||
 | 
					                     )
 | 
				
			||||||
                  => FilePath
 | 
					                  => FilePath
 | 
				
			||||||
                  -> String
 | 
					                  -> String
 | 
				
			||||||
                  -> m ()
 | 
					                  -> m ()
 | 
				
			||||||
@ -816,7 +819,7 @@ setGHC ver sghc = do
 | 
				
			|||||||
          let fullF   = destdir </> sharedir
 | 
					          let fullF   = destdir </> sharedir
 | 
				
			||||||
          let targetF = "." </> "ghc" </> ver' </> sharedir
 | 
					          let targetF = "." </> "ghc" </> ver' </> sharedir
 | 
				
			||||||
          $(logDebug) [i|rm -f #{fullF}|]
 | 
					          $(logDebug) [i|rm -f #{fullF}|]
 | 
				
			||||||
          liftIO $ hideError doesNotExistErrorType $ removeDirectoryLink fullF
 | 
					          hideError doesNotExistErrorType $ rmDirectoryLink fullF
 | 
				
			||||||
          $(logDebug) [i|ln -s #{targetF} #{fullF}|]
 | 
					          $(logDebug) [i|ln -s #{targetF} #{fullF}|]
 | 
				
			||||||
          liftIO
 | 
					          liftIO
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
@ -884,7 +887,7 @@ setHLS ver = do
 | 
				
			|||||||
  oldSyms <- lift hlsSymlinks
 | 
					  oldSyms <- lift hlsSymlinks
 | 
				
			||||||
  forM_ oldSyms $ \f -> do
 | 
					  forM_ oldSyms $ \f -> do
 | 
				
			||||||
    lift $ $(logDebug) [i|rm #{binDir </> f}|]
 | 
					    lift $ $(logDebug) [i|rm #{binDir </> f}|]
 | 
				
			||||||
    liftIO $ rmLink (binDir </> f)
 | 
					    lift $ rmLink (binDir </> f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  -- set haskell-language-server-<ghcver> symlinks
 | 
					  -- set haskell-language-server-<ghcver> symlinks
 | 
				
			||||||
  bins <- lift $ hlsServerBinaries ver
 | 
					  bins <- lift $ hlsServerBinaries ver
 | 
				
			||||||
@ -1307,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}|]
 | 
				
			||||||
  liftIO $ rmPath dir
 | 
					  lift $ rmPathForcibly dir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  v' <-
 | 
					  v' <-
 | 
				
			||||||
    handle
 | 
					    handle
 | 
				
			||||||
@ -1319,7 +1322,7 @@ rmGHCVer ver = do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  Dirs {..} <- lift getDirs
 | 
					  Dirs {..} <- lift getDirs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  liftIO
 | 
					  lift
 | 
				
			||||||
    $ hideError doesNotExistErrorType
 | 
					    $ hideError doesNotExistErrorType
 | 
				
			||||||
    $ rmFile (baseDir </> "share")
 | 
					    $ rmFile (baseDir </> "share")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1346,13 +1349,13 @@ 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
 | 
				
			||||||
  liftIO $ hideError doesNotExistErrorType $ rmFile (binDir </> cabalFile)
 | 
					  lift $ hideError doesNotExistErrorType $ rmFile (binDir </> cabalFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  when (Just ver == cSet) $ do
 | 
					  when (Just ver == cSet) $ do
 | 
				
			||||||
    cVers <- lift $ fmap rights getInstalledCabals
 | 
					    cVers <- lift $ fmap rights getInstalledCabals
 | 
				
			||||||
    case headMay . reverse . sort $ cVers of
 | 
					    case headMay . reverse . sort $ cVers of
 | 
				
			||||||
      Just latestver -> setCabal latestver
 | 
					      Just latestver -> setCabal latestver
 | 
				
			||||||
      Nothing        -> liftIO $ rmLink (binDir </> "cabal" <> exeExt)
 | 
					      Nothing        -> lift $ rmLink (binDir </> "cabal" <> exeExt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Delete a hls version. Will try to fix the hls symlinks
 | 
					-- | Delete a hls version. Will try to fix the hls symlinks
 | 
				
			||||||
@ -1377,7 +1380,7 @@ rmHLSVer ver = do
 | 
				
			|||||||
  Dirs {..} <- lift getDirs
 | 
					  Dirs {..} <- lift getDirs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bins <- lift $ hlsAllBinaries ver
 | 
					  bins <- lift $ hlsAllBinaries ver
 | 
				
			||||||
  forM_ bins $ \f -> liftIO $ rmFile (binDir </> f)
 | 
					  forM_ bins $ \f -> lift $ rmFile (binDir </> f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  when (Just ver == isHlsSet) $ do
 | 
					  when (Just ver == isHlsSet) $ do
 | 
				
			||||||
    -- delete all set symlinks
 | 
					    -- delete all set symlinks
 | 
				
			||||||
@ -1385,7 +1388,7 @@ rmHLSVer ver = do
 | 
				
			|||||||
    forM_ oldSyms $ \f -> do
 | 
					    forM_ oldSyms $ \f -> do
 | 
				
			||||||
      let fullF = binDir </> f
 | 
					      let fullF = binDir </> f
 | 
				
			||||||
      lift $ $(logDebug) [i|rm #{fullF}|]
 | 
					      lift $ $(logDebug) [i|rm #{fullF}|]
 | 
				
			||||||
      liftIO $ rmLink fullF
 | 
					      lift $ rmLink fullF
 | 
				
			||||||
    -- set latest hls
 | 
					    -- set latest hls
 | 
				
			||||||
    hlsVers <- lift $ fmap rights getInstalledHLSs
 | 
					    hlsVers <- lift $ fmap rights getInstalledHLSs
 | 
				
			||||||
    case headMay . reverse . sort $ hlsVers of
 | 
					    case headMay . reverse . sort $ hlsVers of
 | 
				
			||||||
@ -1415,13 +1418,13 @@ 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
 | 
				
			||||||
  liftIO $ hideError doesNotExistErrorType $ rmFile (binDir </> stackFile)
 | 
					  lift $ hideError doesNotExistErrorType $ rmFile (binDir </> stackFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  when (Just ver == sSet) $ do
 | 
					  when (Just ver == sSet) $ do
 | 
				
			||||||
    sVers <- lift $ fmap rights getInstalledStacks
 | 
					    sVers <- lift $ fmap rights getInstalledStacks
 | 
				
			||||||
    case headMay . reverse . sort $ sVers of
 | 
					    case headMay . reverse . sort $ sVers of
 | 
				
			||||||
      Just latestver -> setStack latestver
 | 
					      Just latestver -> setStack latestver
 | 
				
			||||||
      Nothing        -> liftIO $ rmLink (binDir </> "stack" <> exeExt)
 | 
					      Nothing        -> lift $ rmLink (binDir </> "stack" <> exeExt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- assuming the current scheme of having just 1 ghcup bin, no version info is required.
 | 
					-- assuming the current scheme of having just 1 ghcup bin, no version info is required.
 | 
				
			||||||
@ -1430,10 +1433,11 @@ rmGhcup :: ( MonadReader env m
 | 
				
			|||||||
           , MonadIO m
 | 
					           , MonadIO m
 | 
				
			||||||
           , MonadCatch m
 | 
					           , MonadCatch m
 | 
				
			||||||
           , MonadLogger m
 | 
					           , MonadLogger m
 | 
				
			||||||
 | 
					           , MonadMask m
 | 
				
			||||||
           )
 | 
					           )
 | 
				
			||||||
        => m ()
 | 
					        => m ()
 | 
				
			||||||
rmGhcup = do
 | 
					rmGhcup = do
 | 
				
			||||||
  Dirs {binDir} <- getDirs
 | 
					  Dirs { .. } <- getDirs
 | 
				
			||||||
  let ghcupFilename = "ghcup" <> exeExt
 | 
					  let ghcupFilename = "ghcup" <> exeExt
 | 
				
			||||||
  let ghcupFilepath = binDir </> ghcupFilename
 | 
					  let ghcupFilepath = binDir </> ghcupFilename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1457,14 +1461,13 @@ rmGhcup = do
 | 
				
			|||||||
#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 exec in 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
 | 
				
			||||||
  tempDir <- liftIO $ getTemporaryDirectory
 | 
					  let tempFilepath = tmpDir </> ghcupFilename
 | 
				
			||||||
  let tempFilepath = tempDir </> ghcupFilename
 | 
					 | 
				
			||||||
  hideError UnsupportedOperation $
 | 
					  hideError UnsupportedOperation $
 | 
				
			||||||
            liftIO $ hideError NoSuchThing $
 | 
					            liftIO $ hideError NoSuchThing $
 | 
				
			||||||
            Win32.moveFileEx ghcupFilepath (Just tempFilepath) Win32.mOVEFILE_REPLACE_EXISTING
 | 
					            Win32.moveFileEx ghcupFilepath (Just tempFilepath) Win32.mOVEFILE_REPLACE_EXISTING
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  -- delete it.
 | 
					  -- delete it.
 | 
				
			||||||
  hideError doesNotExistErrorType $ liftIO $ rmFile ghcupFilepath
 | 
					  hideError doesNotExistErrorType $ rmFile ghcupFilepath
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  where
 | 
					  where
 | 
				
			||||||
@ -1526,7 +1529,7 @@ rmGhcupDirs = do
 | 
				
			|||||||
  rmDir (baseDir </> "msys64")
 | 
					  rmDir (baseDir </> "msys64")
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  liftIO $ removeEmptyDirsRecursive baseDir
 | 
					  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
 | 
				
			||||||
@ -1534,17 +1537,17 @@ rmGhcupDirs = do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  where
 | 
					  where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rmEnvFile :: (MonadCatch m, MonadLogger m, MonadIO 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
 | 
				
			||||||
      $logInfo "Removing Ghcup Environment File"
 | 
					      $logInfo "Removing Ghcup Environment File"
 | 
				
			||||||
      liftIO $ deleteFile enFilePath
 | 
					      deleteFile enFilePath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rmConfFile :: (MonadCatch m, MonadLogger m, MonadIO m) => FilePath -> m ()
 | 
					    rmConfFile :: (MonadLogger m, MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()
 | 
				
			||||||
    rmConfFile confFilePath = do
 | 
					    rmConfFile confFilePath = do
 | 
				
			||||||
      $logInfo "removing Ghcup Config File"
 | 
					      $logInfo "removing Ghcup Config File"
 | 
				
			||||||
      liftIO $ deleteFile confFilePath
 | 
					      deleteFile confFilePath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rmDir :: (MonadLogger m, MonadIO m, MonadCatch m) => FilePath -> m ()
 | 
					    rmDir :: (MonadLogger m, MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()
 | 
				
			||||||
    rmDir dir =
 | 
					    rmDir dir =
 | 
				
			||||||
      -- 'getDirectoryContentsRecursive' is lazy IO. In case
 | 
					      -- 'getDirectoryContentsRecursive' is lazy IO. In case
 | 
				
			||||||
      -- an error leaks through, we catch it here as well,
 | 
					      -- an error leaks through, we catch it here as well,
 | 
				
			||||||
@ -1552,9 +1555,9 @@ rmGhcupDirs = do
 | 
				
			|||||||
      hideErrorDef [doesNotExistErrorType] () $ do
 | 
					      hideErrorDef [doesNotExistErrorType] () $ do
 | 
				
			||||||
        $logInfo [i|removing #{dir}|]
 | 
					        $logInfo [i|removing #{dir}|]
 | 
				
			||||||
        contents <- liftIO $ getDirectoryContentsRecursive dir
 | 
					        contents <- liftIO $ getDirectoryContentsRecursive dir
 | 
				
			||||||
        forM_ contents (liftIO . deleteFile . (dir </>))
 | 
					        forM_ contents (deleteFile . (dir </>))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rmBinDir :: (MonadCatch m, MonadIO m) => FilePath -> m ()
 | 
					    rmBinDir :: (MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()
 | 
				
			||||||
    rmBinDir binDir = do
 | 
					    rmBinDir binDir = do
 | 
				
			||||||
#if !defined(IS_WINDOWS)
 | 
					#if !defined(IS_WINDOWS)
 | 
				
			||||||
      isXDGStyle <- liftIO useXDG
 | 
					      isXDGStyle <- liftIO useXDG
 | 
				
			||||||
@ -1583,9 +1586,9 @@ rmGhcupDirs = do
 | 
				
			|||||||
        compareFn :: FilePath -> FilePath -> Ordering
 | 
					        compareFn :: FilePath -> FilePath -> Ordering
 | 
				
			||||||
        compareFn fp1 fp2 = compare (calcDepth fp1) (calcDepth fp2)
 | 
					        compareFn fp1 fp2 = compare (calcDepth fp1) (calcDepth fp2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    removeEmptyDirsRecursive :: FilePath -> IO ()
 | 
					    removeEmptyDirsRecursive :: (MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()
 | 
				
			||||||
    removeEmptyDirsRecursive fp = do
 | 
					    removeEmptyDirsRecursive fp = do
 | 
				
			||||||
      cs <- listDirectory fp >>= filterM doesDirectoryExist . fmap (fp </>)
 | 
					      cs <- liftIO $ listDirectory fp >>= filterM doesDirectoryExist . fmap (fp </>)
 | 
				
			||||||
      forM_ cs removeEmptyDirsRecursive
 | 
					      forM_ cs removeEmptyDirsRecursive
 | 
				
			||||||
      hideError InappropriateType $ removeDirIfEmptyOrIsSymlink fp
 | 
					      hideError InappropriateType $ removeDirIfEmptyOrIsSymlink fp
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -1594,22 +1597,22 @@ rmGhcupDirs = do
 | 
				
			|||||||
    -- we report remaining files/dirs later,
 | 
					    -- we report remaining files/dirs later,
 | 
				
			||||||
    -- hence the force/quiet mode in these delete functions below.
 | 
					    -- hence the force/quiet mode in these delete functions below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    deleteFile :: FilePath -> IO ()
 | 
					    deleteFile :: (MonadReader env m, HasDirs env, MonadMask m, MonadIO m) => FilePath -> m ()
 | 
				
			||||||
    deleteFile filepath = do
 | 
					    deleteFile filepath = do
 | 
				
			||||||
      hideError doesNotExistErrorType
 | 
					      hideError doesNotExistErrorType
 | 
				
			||||||
        $ hideError InappropriateType $ rmFile filepath
 | 
					        $ hideError InappropriateType $ rmFile filepath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    removeDirIfEmptyOrIsSymlink :: (MonadCatch m, MonadIO m) => FilePath -> m ()
 | 
					    removeDirIfEmptyOrIsSymlink :: (MonadReader env m, HasDirs env, MonadMask m, MonadIO m, MonadCatch m) => FilePath -> m ()
 | 
				
			||||||
    removeDirIfEmptyOrIsSymlink filepath =
 | 
					    removeDirIfEmptyOrIsSymlink filepath =
 | 
				
			||||||
      hideError UnsatisfiedConstraints $
 | 
					      hideError UnsatisfiedConstraints $
 | 
				
			||||||
      handleIO' InappropriateType
 | 
					      handleIO' InappropriateType
 | 
				
			||||||
            (handleIfSym filepath)
 | 
					            (handleIfSym filepath)
 | 
				
			||||||
            (liftIO $ removeDirectory filepath)
 | 
					            (liftIO $ rmPath filepath)
 | 
				
			||||||
      where
 | 
					      where
 | 
				
			||||||
        handleIfSym fp e = do
 | 
					        handleIfSym fp e = do
 | 
				
			||||||
          isSym <- liftIO $ pathIsSymbolicLink fp
 | 
					          isSym <- liftIO $ pathIsSymbolicLink fp
 | 
				
			||||||
          if isSym
 | 
					          if isSym
 | 
				
			||||||
          then liftIO $ deleteFile fp
 | 
					          then deleteFile fp
 | 
				
			||||||
          else liftIO $ ioError e
 | 
					          else liftIO $ ioError e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2137,8 +2140,8 @@ upgradeGHCup mtarget force' = do
 | 
				
			|||||||
  lift $ $(logDebug) [i|mkdir -p #{destDir}|]
 | 
					  lift $ $(logDebug) [i|mkdir -p #{destDir}|]
 | 
				
			||||||
  liftIO $ createDirRecursive' destDir
 | 
					  liftIO $ createDirRecursive' destDir
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  let tempGhcup = cacheDir </> "ghcup.old"
 | 
					  let tempGhcup = tmpDir </> "ghcup.old"
 | 
				
			||||||
  liftIO $ hideError NoSuchThing $ rmFile tempGhcup
 | 
					  lift $ hideError NoSuchThing $ rmFile tempGhcup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lift $ $(logDebug) [i|mv #{destFile} #{tempGhcup}|]
 | 
					  lift $ $(logDebug) [i|mv #{destFile} #{tempGhcup}|]
 | 
				
			||||||
  -- NoSuchThing may be raised when we're updating ghcup from
 | 
					  -- NoSuchThing may be raised when we're updating ghcup from
 | 
				
			||||||
@ -2149,7 +2152,7 @@ upgradeGHCup mtarget force' = do
 | 
				
			|||||||
                                                           destFile
 | 
					                                                           destFile
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  lift $ $(logDebug) [i|rm -f #{destFile}|]
 | 
					  lift $ $(logDebug) [i|rm -f #{destFile}|]
 | 
				
			||||||
  liftIO $ hideError NoSuchThing $ rmFile destFile
 | 
					  lift $ hideError NoSuchThing $ rmFile 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
 | 
				
			||||||
 | 
				
			|||||||
@ -115,6 +115,7 @@ getDownloadsF :: ( FromJSONKey Tool
 | 
				
			|||||||
                 , MonadLogger m
 | 
					                 , MonadLogger m
 | 
				
			||||||
                 , MonadThrow m
 | 
					                 , MonadThrow m
 | 
				
			||||||
                 , MonadFail m
 | 
					                 , MonadFail m
 | 
				
			||||||
 | 
					                 , MonadMask m
 | 
				
			||||||
                 )
 | 
					                 )
 | 
				
			||||||
              => Excepts
 | 
					              => Excepts
 | 
				
			||||||
                   '[JSONError , DownloadFailed , FileDoesNotExistError]
 | 
					                   '[JSONError , DownloadFailed , FileDoesNotExistError]
 | 
				
			||||||
@ -170,6 +171,7 @@ getBase :: ( MonadReader env m
 | 
				
			|||||||
           , MonadIO m
 | 
					           , MonadIO m
 | 
				
			||||||
           , MonadCatch m
 | 
					           , MonadCatch m
 | 
				
			||||||
           , MonadLogger m
 | 
					           , MonadLogger m
 | 
				
			||||||
 | 
					           , MonadMask m
 | 
				
			||||||
           )
 | 
					           )
 | 
				
			||||||
        => URI
 | 
					        => URI
 | 
				
			||||||
        -> Excepts '[JSONError , FileDoesNotExistError] m GHCupInfo
 | 
					        -> Excepts '[JSONError , FileDoesNotExistError] m GHCupInfo
 | 
				
			||||||
@ -208,6 +210,7 @@ getBase uri = do
 | 
				
			|||||||
             , MonadIO m1
 | 
					             , MonadIO m1
 | 
				
			||||||
             , MonadFail m1
 | 
					             , MonadFail m1
 | 
				
			||||||
             , MonadLogger m1
 | 
					             , MonadLogger m1
 | 
				
			||||||
 | 
					             , MonadMask m1
 | 
				
			||||||
             )
 | 
					             )
 | 
				
			||||||
          => URI
 | 
					          => URI
 | 
				
			||||||
          -> Excepts
 | 
					          -> Excepts
 | 
				
			||||||
@ -262,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'
 | 
				
			||||||
      liftIO $ hideError doesNotExistErrorType $ rmFile json_file
 | 
					      lift $ hideError doesNotExistErrorType $ rmFile 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
 | 
				
			||||||
@ -385,10 +388,10 @@ download dli dest mfn
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    -- download
 | 
					    -- download
 | 
				
			||||||
    flip onException
 | 
					    flip onException
 | 
				
			||||||
         (liftIO $ hideError doesNotExistErrorType $ rmFile destFile)
 | 
					         (lift $ hideError doesNotExistErrorType $ rmFile destFile)
 | 
				
			||||||
     $ catchAllE @_ @'[ProcessError, DownloadFailed, UnsupportedScheme]
 | 
					     $ catchAllE @_ @'[ProcessError, DownloadFailed, UnsupportedScheme]
 | 
				
			||||||
          (\e ->
 | 
					          (\e ->
 | 
				
			||||||
            liftIO (hideError doesNotExistErrorType $ rmFile destFile)
 | 
					            lift (hideError doesNotExistErrorType $ rmFile destFile)
 | 
				
			||||||
              >> (throwE . DownloadFailed $ e)
 | 
					              >> (throwE . DownloadFailed $ e)
 | 
				
			||||||
          ) $ do
 | 
					          ) $ do
 | 
				
			||||||
              Settings{ downloader, noNetwork } <- lift getSettings
 | 
					              Settings{ downloader, noNetwork } <- lift getSettings
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,11 @@
 | 
				
			|||||||
 | 
					{-# OPTIONS_GHC -Wno-orphans #-}
 | 
				
			||||||
{-# LANGUAGE TemplateHaskell       #-}
 | 
					{-# LANGUAGE TemplateHaskell       #-}
 | 
				
			||||||
{-# LANGUAGE ConstraintKinds       #-}
 | 
					{-# LANGUAGE ConstraintKinds       #-}
 | 
				
			||||||
{-# LANGUAGE DataKinds             #-}
 | 
					{-# LANGUAGE DataKinds             #-}
 | 
				
			||||||
{-# LANGUAGE DuplicateRecordFields #-}
 | 
					{-# LANGUAGE DuplicateRecordFields #-}
 | 
				
			||||||
{-# LANGUAGE FlexibleContexts      #-}
 | 
					{-# LANGUAGE FlexibleContexts      #-}
 | 
				
			||||||
{-# LANGUAGE AllowAmbiguousTypes   #-}
 | 
					{-# LANGUAGE AllowAmbiguousTypes   #-}
 | 
				
			||||||
 | 
					{-# LANGUAGE MultiParamTypeClasses   #-}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{-|
 | 
					{-|
 | 
				
			||||||
Module      : GHCup.Types.Optics
 | 
					Module      : GHCup.Types.Optics
 | 
				
			||||||
@ -143,3 +145,6 @@ getCache = getSettings <&> cache
 | 
				
			|||||||
getDownloader :: (MonadReader env m, HasSettings env) => m Downloader
 | 
					getDownloader :: (MonadReader env m, HasSettings env) => m Downloader
 | 
				
			||||||
getDownloader = getSettings <&> downloader
 | 
					getDownloader = getSettings <&> downloader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance LabelOptic "dirs" A_Lens Dirs Dirs Dirs Dirs where
 | 
				
			||||||
 | 
					  labelOptic = lens id (\_ d -> d)
 | 
				
			||||||
 | 
				
			|||||||
@ -123,6 +123,7 @@ rmMinorSymlinks :: ( MonadReader env m
 | 
				
			|||||||
                   , MonadLogger m
 | 
					                   , MonadLogger m
 | 
				
			||||||
                   , MonadThrow m
 | 
					                   , MonadThrow m
 | 
				
			||||||
                   , MonadFail m
 | 
					                   , MonadFail m
 | 
				
			||||||
 | 
					                   , MonadMask m
 | 
				
			||||||
                   )
 | 
					                   )
 | 
				
			||||||
                => GHCTargetVersion
 | 
					                => GHCTargetVersion
 | 
				
			||||||
                -> Excepts '[NotInstalled] m ()
 | 
					                -> Excepts '[NotInstalled] m ()
 | 
				
			||||||
@ -134,7 +135,7 @@ rmMinorSymlinks tv@GHCTargetVersion{..} = do
 | 
				
			|||||||
    let f_xyz = f <> "-" <> T.unpack (prettyVer _tvVersion) <> exeExt
 | 
					    let f_xyz = f <> "-" <> T.unpack (prettyVer _tvVersion) <> exeExt
 | 
				
			||||||
    let fullF = binDir </> f_xyz
 | 
					    let fullF = binDir </> f_xyz
 | 
				
			||||||
    lift $ $(logDebug) [i|rm -f #{fullF}|]
 | 
					    lift $ $(logDebug) [i|rm -f #{fullF}|]
 | 
				
			||||||
    liftIO $ hideError doesNotExistErrorType $ rmLink fullF
 | 
					    lift $ hideError doesNotExistErrorType $ rmLink fullF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Removes the set ghc version for the given target, if any.
 | 
					-- | Removes the set ghc version for the given target, if any.
 | 
				
			||||||
@ -144,6 +145,7 @@ rmPlain :: ( MonadReader env m
 | 
				
			|||||||
           , MonadThrow m
 | 
					           , MonadThrow m
 | 
				
			||||||
           , MonadFail m
 | 
					           , MonadFail m
 | 
				
			||||||
           , MonadIO m
 | 
					           , MonadIO m
 | 
				
			||||||
 | 
					           , MonadMask m
 | 
				
			||||||
           )
 | 
					           )
 | 
				
			||||||
        => Maybe Text -- ^ target
 | 
					        => Maybe Text -- ^ target
 | 
				
			||||||
        -> Excepts '[NotInstalled] m ()
 | 
					        -> Excepts '[NotInstalled] m ()
 | 
				
			||||||
@ -155,11 +157,11 @@ rmPlain target = do
 | 
				
			|||||||
    forM_ files $ \f -> do
 | 
					    forM_ files $ \f -> do
 | 
				
			||||||
      let fullF = binDir </> f <> exeExt
 | 
					      let fullF = binDir </> f <> exeExt
 | 
				
			||||||
      lift $ $(logDebug) [i|rm -f #{fullF}|]
 | 
					      lift $ $(logDebug) [i|rm -f #{fullF}|]
 | 
				
			||||||
      liftIO $ hideError doesNotExistErrorType $ rmLink fullF
 | 
					      lift $ hideError doesNotExistErrorType $ rmLink fullF
 | 
				
			||||||
    -- old ghcup
 | 
					    -- old ghcup
 | 
				
			||||||
    let hdc_file = binDir </> "haddock-ghc" <> exeExt
 | 
					    let hdc_file = binDir </> "haddock-ghc" <> exeExt
 | 
				
			||||||
    lift $ $(logDebug) [i|rm -f #{hdc_file}|]
 | 
					    lift $ $(logDebug) [i|rm -f #{hdc_file}|]
 | 
				
			||||||
    liftIO $ hideError doesNotExistErrorType $ rmLink hdc_file
 | 
					    lift $ hideError doesNotExistErrorType $ rmLink hdc_file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Remove the major GHC symlink, e.g. ghc-8.6.
 | 
					-- | Remove the major GHC symlink, e.g. ghc-8.6.
 | 
				
			||||||
@ -169,6 +171,7 @@ rmMajorSymlinks :: ( MonadReader env m
 | 
				
			|||||||
                   , MonadLogger m
 | 
					                   , MonadLogger m
 | 
				
			||||||
                   , MonadThrow m
 | 
					                   , MonadThrow m
 | 
				
			||||||
                   , MonadFail m
 | 
					                   , MonadFail m
 | 
				
			||||||
 | 
					                   , MonadMask m
 | 
				
			||||||
                   )
 | 
					                   )
 | 
				
			||||||
                => GHCTargetVersion
 | 
					                => GHCTargetVersion
 | 
				
			||||||
                -> Excepts '[NotInstalled] m ()
 | 
					                -> Excepts '[NotInstalled] m ()
 | 
				
			||||||
@ -182,7 +185,7 @@ rmMajorSymlinks tv@GHCTargetVersion{..} = do
 | 
				
			|||||||
    let f_xy = f <> "-" <> T.unpack v' <> exeExt
 | 
					    let f_xy = f <> "-" <> T.unpack v' <> exeExt
 | 
				
			||||||
    let fullF = binDir </> f_xy
 | 
					    let fullF = binDir </> f_xy
 | 
				
			||||||
    lift $ $(logDebug) [i|rm -f #{fullF}|]
 | 
					    lift $ $(logDebug) [i|rm -f #{fullF}|]
 | 
				
			||||||
    liftIO $ hideError doesNotExistErrorType $ rmLink fullF
 | 
					    lift $ hideError doesNotExistErrorType $ rmLink fullF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -892,11 +895,11 @@ runBuildAction bdir instdir action = do
 | 
				
			|||||||
  Settings {..} <- lift getSettings
 | 
					  Settings {..} <- lift getSettings
 | 
				
			||||||
  let exAction = do
 | 
					  let exAction = do
 | 
				
			||||||
        forM_ instdir $ \dir ->
 | 
					        forM_ instdir $ \dir ->
 | 
				
			||||||
          liftIO $ hideError doesNotExistErrorType $ rmPath dir
 | 
					          lift $ hideError doesNotExistErrorType $ rmPathForcibly dir
 | 
				
			||||||
        when (keepDirs == Never)
 | 
					        when (keepDirs == Never)
 | 
				
			||||||
          $ liftIO
 | 
					          $ lift
 | 
				
			||||||
          $ hideError doesNotExistErrorType
 | 
					          $ hideError doesNotExistErrorType
 | 
				
			||||||
          $ rmPath bdir
 | 
					          $ rmPathForcibly bdir
 | 
				
			||||||
  v <-
 | 
					  v <-
 | 
				
			||||||
    flip onException exAction
 | 
					    flip onException exAction
 | 
				
			||||||
    $ catchAllE
 | 
					    $ catchAllE
 | 
				
			||||||
@ -905,7 +908,7 @@ runBuildAction bdir instdir action = do
 | 
				
			|||||||
          throwE (BuildFailed bdir es)
 | 
					          throwE (BuildFailed bdir es)
 | 
				
			||||||
        ) action
 | 
					        ) action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  when (keepDirs == Never || keepDirs == Errors) $ liftIO $ rmPath bdir
 | 
					  when (keepDirs == Never || keepDirs == Errors) $ lift $ rmPathForcibly bdir
 | 
				
			||||||
  pure v
 | 
					  pure v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -995,13 +998,13 @@ pathIsLink = pathIsSymbolicLink
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rmLink :: FilePath -> IO ()
 | 
					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 . liftIO . rmFile $ fp
 | 
					  hideError doesNotExistErrorType . rmFile $ fp
 | 
				
			||||||
  hideError doesNotExistErrorType . liftIO . rmFile $ (dropExtension fp <.> "shim")
 | 
					  hideError doesNotExistErrorType . rmFile $ (dropExtension fp <.> "shim")
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
rmLink = hideError doesNotExistErrorType . liftIO . rmFile
 | 
					rmLink = hideError doesNotExistErrorType . rmFile
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1039,14 +1042,14 @@ createLink link exe = do
 | 
				
			|||||||
      shimContents = "path = " <> fullLink
 | 
					      shimContents = "path = " <> fullLink
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $(logDebug) [i|rm -f #{exe}|]
 | 
					  $(logDebug) [i|rm -f #{exe}|]
 | 
				
			||||||
  liftIO $ rmLink exe
 | 
					  rmLink exe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $(logDebug) [i|ln -s #{fullLink} #{exe}|]
 | 
					  $(logDebug) [i|ln -s #{fullLink} #{exe}|]
 | 
				
			||||||
  liftIO $ copyFile shimGen exe
 | 
					  liftIO $ copyFile shimGen exe
 | 
				
			||||||
  liftIO $ writeFile shim shimContents
 | 
					  liftIO $ writeFile shim shimContents
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  $(logDebug) [i|rm -f #{exe}|]
 | 
					  $(logDebug) [i|rm -f #{exe}|]
 | 
				
			||||||
  liftIO $ hideError doesNotExistErrorType $ rmFile exe
 | 
					  hideError doesNotExistErrorType $ rmFile exe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $(logDebug) [i|ln -s #{link} #{exe}|]
 | 
					  $(logDebug) [i|ln -s #{link} #{exe}|]
 | 
				
			||||||
  liftIO $ createFileLink link exe
 | 
					  liftIO $ createFileLink link exe
 | 
				
			||||||
@ -1068,7 +1071,6 @@ ensureGlobalTools :: ( MonadMask m
 | 
				
			|||||||
ensureGlobalTools = do
 | 
					ensureGlobalTools = do
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  (GHCupInfo _ _ gTools) <- lift getGHCupInfo
 | 
					  (GHCupInfo _ _ gTools) <- lift getGHCupInfo
 | 
				
			||||||
  settings <- lift getSettings
 | 
					 | 
				
			||||||
  dirs <- lift getDirs
 | 
					  dirs <- lift getDirs
 | 
				
			||||||
  shimDownload <- liftE $ lE @_ @'[NoDownload]
 | 
					  shimDownload <- liftE $ lE @_ @'[NoDownload]
 | 
				
			||||||
    $ maybe (Left NoDownload) Right $ Map.lookup ShimGen gTools
 | 
					    $ maybe (Left NoDownload) Right $ Map.lookup ShimGen gTools
 | 
				
			||||||
@ -1076,7 +1078,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}|]
 | 
				
			||||||
      liftIO $ hideError doesNotExistErrorType $ rmFile (cacheDir dirs </> "gs.exe")
 | 
					      lift $ hideError doesNotExistErrorType $ rmFile (cacheDir dirs </> "gs.exe")
 | 
				
			||||||
      liftE @'[DigestError , DownloadFailed] $ dl
 | 
					      liftE @'[DigestError , DownloadFailed] $ dl
 | 
				
			||||||
    ) `catchE` (liftE @'[DigestError , DownloadFailed] dl)
 | 
					    ) `catchE` (liftE @'[DigestError , DownloadFailed] dl)
 | 
				
			||||||
  pure ()
 | 
					  pure ()
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,7 @@ module GHCup.Utils.Dirs
 | 
				
			|||||||
#if !defined(IS_WINDOWS)
 | 
					#if !defined(IS_WINDOWS)
 | 
				
			||||||
  , useXDG
 | 
					  , useXDG
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					  , cleanupGHCupTmp
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -53,9 +54,7 @@ import           Data.String.Interpolate
 | 
				
			|||||||
import           GHC.IO.Exception               ( IOErrorType(NoSuchThing) )
 | 
					import           GHC.IO.Exception               ( IOErrorType(NoSuchThing) )
 | 
				
			||||||
import           Haskus.Utils.Variant.Excepts
 | 
					import           Haskus.Utils.Variant.Excepts
 | 
				
			||||||
import           Optics
 | 
					import           Optics
 | 
				
			||||||
#if !defined(IS_WINDOWS)
 | 
					 | 
				
			||||||
import           System.Directory                                                
 | 
					import           System.Directory                                                
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
import           System.DiskSpace                                                
 | 
					import           System.DiskSpace                                                
 | 
				
			||||||
import           System.Environment
 | 
					import           System.Environment
 | 
				
			||||||
import           System.FilePath
 | 
					import           System.FilePath
 | 
				
			||||||
@ -262,8 +261,20 @@ parseGHCupGHCDir (T.pack -> fp) =
 | 
				
			|||||||
  throwEither $ MP.parse ghcTargetVerP "" fp
 | 
					  throwEither $ MP.parse ghcTargetVerP "" fp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mkGhcupTmpDir :: (MonadUnliftIO m, MonadLogger m, MonadCatch m, MonadThrow m, MonadIO m) => m FilePath
 | 
					mkGhcupTmpDir :: ( MonadReader env m
 | 
				
			||||||
 | 
					                 , HasDirs env
 | 
				
			||||||
 | 
					                 , MonadUnliftIO m
 | 
				
			||||||
 | 
					                 , MonadLogger m
 | 
				
			||||||
 | 
					                 , MonadCatch m
 | 
				
			||||||
 | 
					                 , MonadThrow m
 | 
				
			||||||
 | 
					                 , MonadMask m
 | 
				
			||||||
 | 
					                 , MonadIO m)
 | 
				
			||||||
 | 
					              => 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?
 | 
				
			||||||
@ -281,10 +292,20 @@ 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 :: (MonadUnliftIO m, MonadLogger m, MonadCatch m, MonadResource m, MonadThrow m, MonadIO m) => m FilePath
 | 
					withGHCupTmpDir :: ( MonadReader env m
 | 
				
			||||||
withGHCupTmpDir = snd <$> withRunInIO (\run -> run $ allocate (run mkGhcupTmpDir) rmPath)
 | 
					                   , HasDirs env
 | 
				
			||||||
 | 
					                   , MonadUnliftIO m
 | 
				
			||||||
 | 
					                   , MonadLogger m
 | 
				
			||||||
 | 
					                   , MonadCatch m
 | 
				
			||||||
 | 
					                   , MonadResource m
 | 
				
			||||||
 | 
					                   , MonadThrow m
 | 
				
			||||||
 | 
					                   , MonadMask m
 | 
				
			||||||
 | 
					                   , MonadIO m)
 | 
				
			||||||
 | 
					                => m FilePath
 | 
				
			||||||
 | 
					withGHCupTmpDir = snd <$> withRunInIO (\run -> run $ allocate (run mkGhcupTmpDir) (run . rmPathForcibly))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -312,3 +333,18 @@ relativeSymlink p1 p2 =
 | 
				
			|||||||
        <> joinPath ([pathSeparator] : drop (length common) d2)
 | 
					        <> joinPath ([pathSeparator] : drop (length common) d2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cleanupGHCupTmp :: ( MonadIO m
 | 
				
			||||||
 | 
					                   , MonadMask m
 | 
				
			||||||
 | 
					                   , MonadLogger m
 | 
				
			||||||
 | 
					                   , MonadReader env m
 | 
				
			||||||
 | 
					                   , HasDirs env
 | 
				
			||||||
 | 
					                   )
 | 
				
			||||||
 | 
					                => m ()
 | 
				
			||||||
 | 
					cleanupGHCupTmp = do
 | 
				
			||||||
 | 
					  Dirs { tmpDir } <- getDirs
 | 
				
			||||||
 | 
					  contents <- liftIO $ listDirectory tmpDir
 | 
				
			||||||
 | 
					  if null contents
 | 
				
			||||||
 | 
					  then pure ()
 | 
				
			||||||
 | 
					  else do
 | 
				
			||||||
 | 
					    $(logWarn) [i|Removing leftover files in #{tmpDir}|]
 | 
				
			||||||
 | 
					    forM_ contents (\fp -> liftIO $ removePathForcibly (tmpDir </> fp))
 | 
				
			||||||
 | 
				
			|||||||
@ -14,12 +14,16 @@ Here we define our main logger.
 | 
				
			|||||||
-}
 | 
					-}
 | 
				
			||||||
module GHCup.Utils.Logger where
 | 
					module GHCup.Utils.Logger where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           GHCup.Types
 | 
				
			||||||
 | 
					import           GHCup.Types.Optics
 | 
				
			||||||
import           GHCup.Utils.File
 | 
					import           GHCup.Utils.File
 | 
				
			||||||
import           GHCup.Utils.String.QQ
 | 
					import           GHCup.Utils.String.QQ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import           Control.Exception.Safe
 | 
				
			||||||
import           Control.Monad
 | 
					import           Control.Monad
 | 
				
			||||||
import           Control.Monad.IO.Class
 | 
					import           Control.Monad.IO.Class
 | 
				
			||||||
import           Control.Monad.Logger
 | 
					import           Control.Monad.Logger
 | 
				
			||||||
 | 
					import           Control.Monad.Reader
 | 
				
			||||||
import           Data.Char               ( ord )
 | 
					import           Data.Char               ( ord )
 | 
				
			||||||
import           Prelude                 hiding ( appendFile )
 | 
					import           Prelude                 hiding ( appendFile )
 | 
				
			||||||
import           System.Console.Pretty
 | 
					import           System.Console.Pretty
 | 
				
			||||||
@ -79,17 +83,21 @@ myLoggerT LoggerConfig {..} loggingt = runLoggingT loggingt mylogger
 | 
				
			|||||||
    rawOutter outr
 | 
					    rawOutter outr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
initGHCupFileLogging :: (MonadIO m) => FilePath -> m FilePath
 | 
					initGHCupFileLogging :: ( MonadReader env m
 | 
				
			||||||
initGHCupFileLogging logsDir = do
 | 
					                        , HasDirs env
 | 
				
			||||||
 | 
					                        , MonadIO m
 | 
				
			||||||
 | 
					                        , MonadMask m
 | 
				
			||||||
 | 
					                        ) => m FilePath
 | 
				
			||||||
 | 
					initGHCupFileLogging = do
 | 
				
			||||||
 | 
					  Dirs { logsDir } <- getDirs
 | 
				
			||||||
  let logfile = logsDir </> "ghcup.log"
 | 
					  let logfile = logsDir </> "ghcup.log"
 | 
				
			||||||
  liftIO $ do
 | 
					  logFiles <- liftIO $ findFiles
 | 
				
			||||||
    logFiles <- findFiles
 | 
					    logsDir
 | 
				
			||||||
      logsDir
 | 
					    (makeRegexOpts compExtended
 | 
				
			||||||
      (makeRegexOpts compExtended
 | 
					                   execBlank
 | 
				
			||||||
                     execBlank
 | 
					                   ([s|^.*\.log$|] :: B.ByteString)
 | 
				
			||||||
                     ([s|^.*\.log$|] :: B.ByteString)
 | 
					    )
 | 
				
			||||||
      )
 | 
					  forM_ logFiles $ hideError doesNotExistErrorType . rmFile . (logsDir </>)
 | 
				
			||||||
    forM_ logFiles $ hideError doesNotExistErrorType . rmFile . (logsDir </>)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    writeFile logfile ""
 | 
					  liftIO $ writeFile logfile ""
 | 
				
			||||||
    pure logfile
 | 
					  pure logfile
 | 
				
			||||||
 | 
				
			|||||||
@ -19,11 +19,16 @@ GHCup specific prelude. Lots of Excepts functionality.
 | 
				
			|||||||
-}
 | 
					-}
 | 
				
			||||||
module GHCup.Utils.Prelude where
 | 
					module GHCup.Utils.Prelude where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					import           GHCup.Types
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					import           GHCup.Types.Optics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import           Control.Applicative
 | 
					import           Control.Applicative
 | 
				
			||||||
import           Control.Exception.Safe
 | 
					import           Control.Exception.Safe
 | 
				
			||||||
import           Control.Monad
 | 
					import           Control.Monad
 | 
				
			||||||
import           Control.Monad.IO.Class
 | 
					import           Control.Monad.IO.Class
 | 
				
			||||||
import           Control.Monad.Trans.Class      ( lift )
 | 
					import           Control.Monad.Reader
 | 
				
			||||||
import           Data.Bifunctor
 | 
					import           Data.Bifunctor
 | 
				
			||||||
import           Data.ByteString                ( ByteString )
 | 
					import           Data.ByteString                ( ByteString )
 | 
				
			||||||
import           Data.List                      ( nub )
 | 
					import           Data.List                      ( nub )
 | 
				
			||||||
@ -35,6 +40,9 @@ import           Data.Word8
 | 
				
			|||||||
import           Haskus.Utils.Types.List
 | 
					import           Haskus.Utils.Types.List
 | 
				
			||||||
import           Haskus.Utils.Variant.Excepts
 | 
					import           Haskus.Utils.Variant.Excepts
 | 
				
			||||||
import           System.IO.Error
 | 
					import           System.IO.Error
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					import           System.IO.Temp
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
import           System.IO.Unsafe
 | 
					import           System.IO.Unsafe
 | 
				
			||||||
import           System.Directory
 | 
					import           System.Directory
 | 
				
			||||||
import           System.FilePath
 | 
					import           System.FilePath
 | 
				
			||||||
@ -54,6 +62,9 @@ import qualified Data.Text.Lazy                as TL
 | 
				
			|||||||
import qualified Data.Text.Lazy.Builder        as B
 | 
					import qualified Data.Text.Lazy.Builder        as B
 | 
				
			||||||
import qualified Data.Text.Lazy.Builder.Int    as B
 | 
					import qualified Data.Text.Lazy.Builder.Int    as B
 | 
				
			||||||
import qualified Data.Text.Lazy.Encoding       as TLE
 | 
					import qualified Data.Text.Lazy.Encoding       as TLE
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					import qualified System.Win32.File             as Win32
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -370,9 +381,33 @@ getDirectoryContentsRecursive topdir = recurseDirectories [""]
 | 
				
			|||||||
-- 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
 | 
				
			||||||
 | 
					                  , MonadReader env m
 | 
				
			||||||
 | 
					                  , HasDirs env
 | 
				
			||||||
 | 
					                  , MonadMask m
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
 | 
					               => FilePath
 | 
				
			||||||
 | 
					               -> m ()
 | 
				
			||||||
 | 
					rmPathForcibly fp = do
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					  Dirs { tmpDir } <- getDirs
 | 
				
			||||||
 | 
					  tmp <- liftIO $ createTempDirectory tmpDir "rmPathForcibly"
 | 
				
			||||||
 | 
					  let dest = tmp </> takeFileName fp
 | 
				
			||||||
 | 
					  liftIO (Win32.moveFileEx fp (Just dest) 0)
 | 
				
			||||||
 | 
					      `finally`
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					  liftIO $ removeDirectoryRecursive fp
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rmPath :: (MonadIO m, MonadMask m)
 | 
					rmPath :: (MonadIO m, MonadMask m)
 | 
				
			||||||
      => FilePath
 | 
					       => FilePath
 | 
				
			||||||
      -> m ()
 | 
					       -> m ()
 | 
				
			||||||
rmPath fp =
 | 
					rmPath fp =
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
					  recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
				
			||||||
@ -380,24 +415,46 @@ rmPath fp =
 | 
				
			|||||||
    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
 | 
				
			||||||
    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
 | 
					    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    (\_ -> liftIO $ removePathForcibly fp)
 | 
					    (\_ -> liftIO $ removeDirectory fp)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  liftIO $ removeDirectoryRecursive fp
 | 
					  liftIO $ removeDirectory fp
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- 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
 | 
				
			||||||
rmFile :: (MonadIO m, MonadMask m)
 | 
					rmFile :: ( MonadIO m
 | 
				
			||||||
 | 
					          , MonadMask m
 | 
				
			||||||
 | 
					          , MonadReader env m
 | 
				
			||||||
 | 
					          , HasDirs env
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
      => FilePath
 | 
					      => FilePath
 | 
				
			||||||
      -> m ()
 | 
					      -> m ()
 | 
				
			||||||
rmFile fp =
 | 
					rmFile fp = do
 | 
				
			||||||
#if defined(IS_WINDOWS)
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
  recovering (fullJitterBackoff 25000 <> limitRetries 10)
 | 
					  Dirs { tmpDir } <- getDirs
 | 
				
			||||||
    [\_ -> Handler (\e -> pure $ isPermissionError e)
 | 
					  liftIO $ whenM (doesDirectoryExist fp) $ ioError (IOError Nothing InappropriateType "rmFile" "" Nothing (Just fp))
 | 
				
			||||||
    ,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
 | 
					  tmp <- liftIO $ createTempDirectory tmpDir "rmFile"
 | 
				
			||||||
    ]
 | 
					  let dest = tmp </> takeFileName fp
 | 
				
			||||||
    (\_ -> liftIO $ removeFile fp)
 | 
					  liftIO (Win32.moveFileEx fp (Just dest) 0)
 | 
				
			||||||
 | 
					    `finally`
 | 
				
			||||||
 | 
					      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
 | 
				
			||||||
 | 
					  liftIO $ removeFile fp
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rmDirectoryLink :: (MonadIO m, MonadMask m, MonadReader env m, HasDirs env)
 | 
				
			||||||
 | 
					                => FilePath
 | 
				
			||||||
 | 
					                -> m ()
 | 
				
			||||||
 | 
					rmDirectoryLink fp = 
 | 
				
			||||||
 | 
					#if defined(IS_WINDOWS)
 | 
				
			||||||
 | 
					  rmPathForcibly fp
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  liftIO $ removeFile fp
 | 
					  liftIO $ removeFile fp
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user