From 179c1238121fb9b089f9d986b62b6936666f2971 Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Fri, 22 May 2026 23:21:35 +0800 Subject: [PATCH 1/3] Fix check-pr-labels --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4a22ce8515b..b3cac89ba2d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -29,7 +29,7 @@ jobs: - id: gen_output run: | if [ "${{ github.event.action }}" == 'labeled' ] ; then - if [ ${{ github.event.label.name == '${{ env.BUILD_LABEL }}' }} ] ; then + if [ "${{ github.event.label.name }}" == "${{ env.BUILD_LABEL }}" ] ; then echo run_release_workflow="yes" >> "$GITHUB_OUTPUT" else echo run_release_workflow="no" >> "$GITHUB_OUTPUT" From d7bf01245085ca88182ab9487e629872e73dec4f Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sat, 23 May 2026 00:22:53 +0800 Subject: [PATCH 2/3] Fix windows CI --- .github/workflows/reusable-release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/reusable-release.yml b/.github/workflows/reusable-release.yml index 81cf9db0aa2..618ba83031e 100644 --- a/.github/workflows/reusable-release.yml +++ b/.github/workflows/reusable-release.yml @@ -364,7 +364,6 @@ jobs: TARBALL_EXT: "zip" DISTRO: na CABAL_DIR: "C:\\Users\\runneradmin\\AppData\\Roaming\\cabal" - GHCUP_INSTALL_BASE_PREFIX: "/c" strategy: fail-fast: false matrix: From d8ba5e8a32b0a969a34fef211a3032908390f412 Mon Sep 17 00:00:00 2001 From: Bodigrim Date: Sat, 23 May 2026 21:59:13 +0100 Subject: [PATCH 3/3] Fix createTempDirectory name generation The existing `createTempDirectory` uses a suboptimal schema to generate temporary directory names. Namely, it starts with `foo-$processId`. If there is no such folder that's it, otherwise it tries to create `foo-($processId+1)`, then `foo-($processId+2)`, etc. While on the surface this is OK, in practice it puts strain on the file system. If we need to create N temporary folders, the name assignment will cycle starting from `foo-$processid` every time, totaling N^2 IO calls. There are also seem to be issues on Windows when one thread is removing its temporary folder, while another it trying to create the very same one. It would be so much better if our temporary names were more diverse by construction. Yes, there might be an odd chance of a clash because someone else just accidentally created the very same folder, but we should not routinely make our own life harder. Normally this is achieved by generating random numbers, but Cabal cannot depend on non-boot libraries such as `random`. So this patch uses a global counter. The approach is similar to one used by [`file-io`](https://hackage-content.haskell.org/package/file-io-0.2.0/docs/src/System.File.Platform.html#tempCounter) for temporary files or by [`temporary-ospath`](https://hackage-content.haskell.org/package/temporary-ospath-1.3/docs/src/System.IO.Temp.OsPath.html#tempDirectoryCounter). (Both `file-io` and `temporary-ospath` actually have even more refined schema for name generation, getting entropy from CPU time, but I think in the interest of simplicity Cabal can get away just with a global counter) --- .../Distribution/Compat/Internal/TempFile.hs | 29 +++++++++++-------- changelog.d/pr-11872.md | 7 +++++ 2 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 changelog.d/pr-11872.md diff --git a/Cabal/src/Distribution/Compat/Internal/TempFile.hs b/Cabal/src/Distribution/Compat/Internal/TempFile.hs index 0d20c69ec4a..f95568fc97d 100644 --- a/Cabal/src/Distribution/Compat/Internal/TempFile.hs +++ b/Cabal/src/Distribution/Compat/Internal/TempFile.hs @@ -10,10 +10,11 @@ module Distribution.Compat.Internal.TempFile import Distribution.Compat.Exception +import GHC.IORef (IORef, atomicModifyIORef'_, newIORef) import System.FilePath (()) - import System.IO (Handle, openBinaryTempFile, openBinaryTempFileWithDefaultPermissions, openTempFile) import System.IO.Error (isAlreadyExistsError) +import System.IO.Unsafe (unsafePerformIO) import System.Posix.Internals (c_getpid) #if defined(mingw32_HOST_OS) || defined(ghcjs_HOST_OS) @@ -28,17 +29,21 @@ openNewBinaryFile = openBinaryTempFileWithDefaultPermissions createTempDirectory :: FilePath -> String -> IO FilePath createTempDirectory dir template = do pid <- c_getpid - findTempName pid - where - findTempName x = do - let relpath = template ++ "-" ++ show x - dirpath = dir relpath - r <- tryIO $ mkPrivateDir dirpath - case r of - Right _ -> return relpath - Left e - | isAlreadyExistsError e -> findTempName (x + 1) - | otherwise -> ioError e + let findTempName = do + (counter, _) <- atomicModifyIORef'_ tempDirectoryCounter (+ 1) + let relpath = template ++ "-" ++ show pid ++ show counter + dirpath = dir relpath + r <- tryIO $ mkPrivateDir dirpath + case r of + Right _ -> pure relpath + Left e + | isAlreadyExistsError e -> findTempName + | otherwise -> ioError e + findTempName + +tempDirectoryCounter :: IORef Word +tempDirectoryCounter = unsafePerformIO $ newIORef 0 +{-# NOINLINE tempDirectoryCounter #-} mkPrivateDir :: String -> IO () #if defined(mingw32_HOST_OS) || defined(ghcjs_HOST_OS) diff --git a/changelog.d/pr-11872.md b/changelog.d/pr-11872.md new file mode 100644 index 00000000000..1fa197eb65a --- /dev/null +++ b/changelog.d/pr-11872.md @@ -0,0 +1,7 @@ +--- +synopsis: Improve name assigning for temporary folders +packages: [Cabal,cabal-install] +prs: 11872 +--- + +Now `createTempDirectory` from `Distribution.Compat.Internal.TempFile` uses a global counter as a part of temporary folder name template, so that probing is less likely to fail. The change should be invisible for users.