Blob Blame History Raw
From 9aace0eaf6279f17368a1753b65afbdc466e8291 Mon Sep 17 00:00:00 2001
From: Sylvain Henry <sylvain@haskus.fr>
Date: Sat, 10 Apr 2021 14:48:16 +0200
Subject: [PATCH] Produce constant file atomically (#19684)

---
 utils/deriveConstants/Main.hs               | 21 ++++++++++++++++-----
 utils/deriveConstants/deriveConstants.cabal |  3 ++-
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/utils/deriveConstants/Main.hs b/utils/deriveConstants/Main.hs
index 8bf8ae7b44d..9db673a9852 100644
--- a/utils/deriveConstants/Main.hs
+++ b/utils/deriveConstants/Main.hs
@@ -34,9 +34,10 @@ import Data.Maybe (catMaybes, mapMaybe, fromMaybe)
 import Numeric (readHex)
 import System.Environment (getArgs)
 import System.Exit (ExitCode(ExitSuccess), exitFailure)
-import System.FilePath ((</>))
+import System.FilePath ((</>),(<.>))
 import System.IO (stderr, hPutStrLn)
 import System.Process (showCommandForUser, readProcess, rawSystem)
+import System.Directory (renameFile)
 
 main :: IO ()
 main = do opts <- parseArgs
@@ -79,6 +80,16 @@ data Options = Options {
                    o_targetOS :: Maybe String
                }
 
+-- | Write a file atomically
+--
+-- This avoids other processes seeing the file while it is being written into.
+atomicWriteFile :: FilePath -> String -> IO ()
+atomicWriteFile fn s = do
+  let tmp = fn <.> "tmp"
+  writeFile tmp s
+  renameFile tmp fn
+
+
 parseArgs :: IO Options
 parseArgs = do args <- getArgs
                opts <- f emptyOptions args
@@ -670,7 +681,7 @@ getWanted verbose os tmpdir gccProgram gccFlags nmProgram mobjdumpProgram
     = do let cStuff = unlines (headers ++ concatMap (doWanted . snd) (wanteds os))
              cFile = tmpdir </> "tmp.c"
              oFile = tmpdir </> "tmp.o"
-         writeFile cFile cStuff
+         atomicWriteFile cFile cStuff
          execute verbose gccProgram (gccFlags ++ ["-c", cFile, "-o", oFile])
          xs <- case os of
                  "openbsd" -> readProcess objdumpProgam ["--syms", oFile] ""
@@ -855,7 +866,7 @@ getWanted verbose os tmpdir gccProgram gccFlags nmProgram mobjdumpProgram
               = return (w, FieldTypeGcptrMacro name)
 
 writeHaskellType :: FilePath -> [What Fst] -> IO ()
-writeHaskellType fn ws = writeFile fn xs
+writeHaskellType fn ws = atomicWriteFile fn xs
     where xs = unlines [header, body, footer, parser]
           header = "module GHC.Platform.Constants where\n\n\
                    \import Prelude\n\
@@ -920,7 +931,7 @@ writeHaskellType fn ws = writeFile fn xs
 
 
 writeHaskellValue :: FilePath -> [What Snd] -> IO ()
-writeHaskellValue fn rs = writeFile fn xs
+writeHaskellValue fn rs = atomicWriteFile fn xs
     where xs = unlines [header, body, footer]
           header = "PlatformConstants {"
           footer = "  }"
@@ -937,7 +948,7 @@ writeHaskellValue fn rs = writeFile fn xs
           doWhat (FieldTypeGcptrMacro {}) = []
 
 writeHeader :: FilePath -> [(Where, What Snd)] -> IO ()
-writeHeader fn rs = writeFile fn xs
+writeHeader fn rs = atomicWriteFile fn xs
     where xs = headers ++ hs ++ unlines body
           headers = "/* This file is created automatically.  Do not edit by hand.*/\n\n"
           haskellRs = fmap snd $ filter (\r -> fst r `elem` [Haskell,Both]) rs
diff --git a/utils/deriveConstants/deriveConstants.cabal b/utils/deriveConstants/deriveConstants.cabal
index 50b5b695c30..36ba7ebe1f7 100644
--- a/utils/deriveConstants/deriveConstants.cabal
+++ b/utils/deriveConstants/deriveConstants.cabal
@@ -20,4 +20,5 @@ Executable deriveConstants
     Build-Depends: base       >= 4   && < 5,
                    containers,
                    process,
-                   filepath
+                   filepath,
+                   directory
-- 
GitLab