1 % Copyright (C) 2005 Tomasz Zielonka
3 % This program is free software; you can redistribute it and/or modify
4 % it under the terms of the GNU General Public License as published by
5 % the Free Software Foundation; either version 2, or (at your option)
8 % This program is distributed in the hope that it will be useful,
9 % but WITHOUT ANY WARRANTY; without even the implied warranty of
10 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 % GNU General Public License for more details.
13 % You should have received a copy of the GNU General Public License
14 % along with this program; see the file COPYING. If not, write to
15 % the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 % Boston, MA 02110-1301, USA.
19 This was originally Tomasz Zielonka's AtExit module, slightly generalised
20 to include global variables. Here, we attempt to cover broad, global
21 features, such as exit handlers. These features slightly break the Haskellian
22 purity of darcs, in favour of programming convenience.
25 module Darcs.Global ( atexit, with_atexit,
26 sshControlMasterDisabled, setSshControlMasterDisabled,
27 verboseMode, setVerboseMode,
28 timingsMode, setTimingsMode,
29 whenDebugMode, withDebugMode, setDebugMode,
30 debugMessage, debugFail, putTiming,
34 import Control.Monad ( when )
35 import Control.Concurrent.MVar
36 import Control.Exception (bracket_, catch, block, unblock)
37 import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
38 import System.IO.Unsafe (unsafePerformIO)
39 import System.IO (hPutStrLn, hPutStr, stderr)
40 import System.Time ( calendarTimeToString, toCalendarTime, getClockTime )
41 import Prelude hiding (catch)
43 {-# NOINLINE atexit_actions #-}
44 atexit_actions :: MVar (Maybe [IO ()])
45 atexit_actions = unsafePerformIO (newMVar (Just []))
47 atexit :: IO () -> IO ()
49 modifyMVar_ atexit_actions $ \ml -> do
52 return (Just (action : l))
54 hPutStrLn stderr "It's too late to use atexit"
57 with_atexit :: IO a -> IO a
65 Just actions <- swapMVar atexit_actions Nothing
66 -- from now on atexit will not register new actions
67 mapM_ runAction actions
69 catch (unblock action) $ \exn -> do
70 hPutStrLn stderr $ "Exception thrown by an atexit registered action:"
71 hPutStrLn stderr $ show exn
75 Write-once-read-many global variables make it easier to implement flags, such
76 as --no-ssh-cm. Using global variables reduces the number of parameters
77 that we have to pass around, but it is rather unsafe and should be used sparingly.
80 {-# NOINLINE _debugMode #-}
81 _debugMode :: IORef Bool
82 _debugMode = unsafePerformIO $ newIORef False
85 setDebugMode = writeIORef _debugMode True
87 whenDebugMode :: IO () -> IO ()
88 whenDebugMode j = do b <- readIORef _debugMode
91 withDebugMode :: (Bool -> IO a) -> IO a
92 withDebugMode j = readIORef _debugMode >>= j
95 debugMessage :: String -> IO ()
96 debugMessage m = whenDebugMode $ do putTiming; hPutStrLn stderr m
98 debugFail :: String -> IO a
99 debugFail m = debugMessage m >> fail m
102 putTiming = when timingsMode $ do t <- getClockTime >>= toCalendarTime
103 hPutStr stderr (calendarTimeToString t++": ")
105 {-# NOINLINE _timingsMode #-}
106 _timingsMode :: IORef Bool
107 _timingsMode = unsafePerformIO $ newIORef False
109 setTimingsMode :: IO ()
110 setTimingsMode = writeIORef _timingsMode True
112 {-# NOINLINE timingsMode #-}
114 timingsMode = unsafePerformIO $ readIORef _timingsMode
116 {-# NOINLINE _verboseMode #-}
117 _verboseMode :: IORef Bool
118 _verboseMode = unsafePerformIO $ newIORef False
120 setVerboseMode :: IO ()
121 setVerboseMode = writeIORef _verboseMode True
123 {-# NOINLINE verboseMode #-}
125 verboseMode = unsafePerformIO $ readIORef _verboseMode
127 {-# NOINLINE _sshControlMasterDisabled #-}
128 _sshControlMasterDisabled :: IORef Bool
129 _sshControlMasterDisabled = unsafePerformIO $ newIORef False
131 setSshControlMasterDisabled :: IO ()
132 setSshControlMasterDisabled = writeIORef _sshControlMasterDisabled True
134 {-# NOINLINE sshControlMasterDisabled #-}
135 sshControlMasterDisabled :: Bool
136 sshControlMasterDisabled = unsafePerformIO $ readIORef _sshControlMasterDisabled