-- Copyright (C) 2005 Tomasz Zielonka---- This program is free software; you can redistribute it and/or modify-- it under the terms of the GNU General Public License as published by-- the Free Software Foundation; either version 2, or (at your option)-- any later version.---- This program is distributed in the hope that it will be useful,-- but WITHOUT ANY WARRANTY; without even the implied warranty of-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-- GNU General Public License for more details.---- You should have received a copy of the GNU General Public License-- along with this program; see the file COPYING. If not, write to-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,-- Boston, MA 02110-1301, USA.{-# LANGUAGE CPP #-}-- | This was originally Tomasz Zielonka's AtExit module, slightly generalised-- to include global variables. Here, we attempt to cover broad, global-- features, such as exit handlers. These features slightly break the Haskellian-- purity of darcs, in favour of programming convenience.moduleDarcs.Global(atexit,withAtexit,sshControlMasterDisabled,setSshControlMasterDisabled,verboseMode,setVerboseMode,timingsMode,setTimingsMode,whenDebugMode,withDebugMode,setDebugMode,debugMessage,debugFail,putTiming,addCRCWarning,getCRCWarnings,resetCRCWarnings,darcsdir)whereimportControl.Monad(when)importControl.Concurrent.MVarimportControl.Exception.Extensible(bracket_,catch,block,unblock,SomeException)importData.IORef(IORef,newIORef,readIORef,writeIORef)importData.IORef(modifyIORef)importSystem.IO.Unsafe(unsafePerformIO)importSystem.IO(hPutStrLn,hPutStr,stderr)importSystem.Time(calendarTimeToString,toCalendarTime,getClockTime)importPreludehiding(catch){-# NOINLINE atexitActions #-}atexitActions::MVar(Maybe[IO()])atexitActions=unsafePerformIO(newMVar(Just[]))-- | Registers an IO action to run just before darcs exits. Useful-- for removing temporary files and directories, for example.atexit::IO()->IO()atexitaction=domodifyMVar_atexitActions$\ml->docasemlofJustl->doreturn(Just(action:l))Nothing->dohPutStrLnstderr"It's too late to use atexit"returnNothingwithAtexit::IOa->IOawithAtexitprog=dobracket_(return())exitprogwhereexit=block$doJustactions<-swapMVaratexitActionsNothing-- from now on atexit will not register new actionsmapM_runActionactionsrunActionaction=docatch(unblockaction)$\(exn::SomeException)->dohPutStrLnstderr$"Exception thrown by an atexit registered action:"hPutStrLnstderr$showexn-- Write-once-read-many global variables make it easier to implement flags, such-- as --no-ssh-cm. Using global variables reduces the number of parameters-- that we have to pass around, but it is rather unsafe and should be used sparingly.{-# NOINLINE _debugMode #-}_debugMode::IORefBool_debugMode=unsafePerformIO$newIORefFalsesetDebugMode::IO()setDebugMode=writeIORef_debugModeTruewhenDebugMode::IO()->IO()whenDebugModej=dob<-readIORef_debugModewhenbjwithDebugMode::(Bool->IOa)->IOawithDebugModej=readIORef_debugMode>>=jdebugMessage::String->IO()debugMessagem=whenDebugMode$doputTiming;hPutStrLnstderrmdebugFail::String->IOadebugFailm=debugMessagem>>failmputTiming::IO()putTiming=whentimingsMode$dot<-getClockTime>>=toCalendarTimehPutStrstderr(calendarTimeToStringt++": "){-# NOINLINE _timingsMode #-}_timingsMode::IORefBool_timingsMode=unsafePerformIO$newIORefFalsesetTimingsMode::IO()setTimingsMode=writeIORef_timingsModeTrue{-# NOINLINE timingsMode #-}timingsMode::BooltimingsMode=unsafePerformIO$readIORef_timingsMode{-# NOINLINE _verboseMode #-}_verboseMode::IORefBool_verboseMode=unsafePerformIO$newIORefFalsesetVerboseMode::IO()setVerboseMode=writeIORef_verboseModeTrue{-# NOINLINE verboseMode #-}verboseMode::BoolverboseMode=unsafePerformIO$readIORef_verboseMode{-# NOINLINE _sshControlMasterDisabled #-}_sshControlMasterDisabled::IORefBool_sshControlMasterDisabled=unsafePerformIO$newIORefFalsesetSshControlMasterDisabled::IO()setSshControlMasterDisabled=writeIORef_sshControlMasterDisabledTrue{-# NOINLINE sshControlMasterDisabled #-}sshControlMasterDisabled::BoolsshControlMasterDisabled=unsafePerformIO$readIORef_sshControlMasterDisabledtypeCRCWarningList=[FilePath]{-# NOINLINE _crcWarningList #-}_crcWarningList::IORefCRCWarningList_crcWarningList=unsafePerformIO$newIORef[]addCRCWarning::FilePath->IO()addCRCWarningfp=modifyIORef_crcWarningList(fp:)getCRCWarnings::IO[FilePath]getCRCWarnings=readIORef_crcWarningListresetCRCWarnings::IO()resetCRCWarnings=writeIORef_crcWarningList[]darcsdir::Stringdarcsdir="_darcs"