summaryrefslogtreecommitdiff
path: root/src/Propellor/Property/File.hs
diff options
context:
space:
mode:
authorJoey Hess2015-10-14 13:10:07 -0400
committerJoey Hess2015-10-14 13:10:07 -0400
commit037d287a3a383471edbcd4cf8f490fc4027b67b7 (patch)
treef82c33311ae7a1731a329d40f7643ebed0d60c7b /src/Propellor/Property/File.hs
parentbbb0386515365b6735a9e635baa38fe762c951ef (diff)
fileProperty, and properties derived from it now write the new file content via origfile.propellor-new~, instead of to a randomly named temp file.
This allows them to clean up any temp file that may have been left by an interrupted run of propellor. Also converted the new isSymlinkedTo property to use the same implementation, with some simplifications.
Diffstat (limited to 'src/Propellor/Property/File.hs')
-rw-r--r--src/Propellor/Property/File.hs43
1 files changed, 27 insertions, 16 deletions
diff --git a/src/Propellor/Property/File.hs b/src/Propellor/Property/File.hs
index f774272c..12a3e80a 100644
--- a/src/Propellor/Property/File.hs
+++ b/src/Propellor/Property/File.hs
@@ -82,12 +82,11 @@ fileProperty' writer desc a f = property desc $ go =<< liftIO (doesFileExist f)
let new = unlines (a (lines old))
if old == new
then noChange
- else makeChange $ viaTmp updatefile f new
+ else makeChange $ updatefile new `viaStableTmp` f
go False = makeChange $ writer f (unlines $ a [])
- -- viaTmp makes the temp file mode 600.
-- Replicate the original file's owner and mode.
- updatefile f' content = do
+ updatefile content f' = do
writer f' content
s <- getFileStatus f
setFileMode f' (fileMode s)
@@ -119,19 +118,7 @@ link `isSymlinkedTo` target = property desc $
if target == target'
then noChange
else makeChange updateLink
- updateLink = bracket_ setup cleanup $ rename link' link
- link' = link ++ ".propellor-new~"
- setup = do
- whenM hasOldLink' removeOldLink'
- createSymbolicLink target link'
- cleanup = tryIO $ removeLink link'
- hasOldLink' = (tryIO $ getSymbolicLinkStatus link') >>= \result ->
- case result of
- Right stat -> return $ isSymbolicLink stat
- Left _ -> return False
- removeOldLink' = do
- warningMessage $ "removing cruft from previous run: " ++ link'
- removeLink link'
+ updateLink = createSymbolicLink target `viaStableTmp` link
-- | Ensures that a file/dir has the specified owner and group.
ownerGroup :: FilePath -> User -> Group -> Property NoInfo
@@ -148,3 +135,27 @@ mode :: FilePath -> FileMode -> Property NoInfo
mode f v = property (f ++ " mode " ++ show v) $ do
liftIO $ modifyFileMode f (const v)
noChange
+
+-- | A temp file to use when writing new content for a file.
+--
+-- This is a stable name so it can be removed idempotently.
+--
+-- It ends with "~" so that programs that read many config files from a
+-- directory will treat it as an editor backup file, and not read it.
+stableTmpFor :: FilePath -> FilePath
+stableTmpFor f = f ++ ".propellor-new~"
+
+-- | Creates/updates a file atomically, running the action to create the
+-- stable tmp file, and then renaming it into place.
+viaStableTmp :: (MonadMask m, MonadIO m) => (FilePath -> m ()) -> FilePath -> m ()
+viaStableTmp a f = bracketIO setup cleanup go
+ where
+ setup = do
+ createDirectoryIfMissing True (takeDirectory f)
+ let tmpfile = stableTmpFor f
+ nukeFile tmpfile
+ return tmpfile
+ cleanup tmpfile = tryIO $ removeFile tmpfile
+ go tmpfile = do
+ a tmpfile
+ liftIO $ rename tmpfile f