2013-11-22 22:46:45 +00:00
|
|
|
{- git-annex assistant thread to detect when git-annex binary is changed
|
|
|
|
-
|
|
|
|
- Copyright 2013 Joey Hess <joey@kitenet.net>
|
|
|
|
-
|
|
|
|
- Licensed under the GNU GPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
2013-11-23 03:12:06 +00:00
|
|
|
{-# LANGUAGE CPP #-}
|
|
|
|
|
2013-11-22 22:46:45 +00:00
|
|
|
module Assistant.Threads.UpgradeWatcher (
|
|
|
|
upgradWatcherThread
|
|
|
|
) where
|
|
|
|
|
|
|
|
import Assistant.Common
|
|
|
|
import Utility.DirWatcher
|
|
|
|
import Utility.DirWatcher.Types
|
|
|
|
import Config.Files
|
2013-11-23 03:12:06 +00:00
|
|
|
import qualified Utility.Lsof as Lsof
|
|
|
|
import Utility.ThreadScheduler
|
|
|
|
import Assistant.Types.UrlRenderer
|
|
|
|
import Assistant.Alert
|
|
|
|
import Assistant.DaemonStatus
|
|
|
|
#ifdef WITH_WEBAPP
|
|
|
|
import Assistant.WebApp.Types
|
|
|
|
#endif
|
2013-11-22 22:46:45 +00:00
|
|
|
|
|
|
|
import Control.Concurrent.MVar
|
2013-11-23 03:12:06 +00:00
|
|
|
import Data.Tuple.Utils
|
|
|
|
import qualified Data.Text as T
|
2013-11-22 22:46:45 +00:00
|
|
|
|
|
|
|
data WatcherState = InStartupScan | Started | Upgrading
|
|
|
|
deriving (Eq)
|
|
|
|
|
2013-11-23 03:12:06 +00:00
|
|
|
upgradWatcherThread :: UrlRenderer -> NamedThread
|
|
|
|
upgradWatcherThread urlrenderer = namedThread "UpgradeWatcher" $ go =<< liftIO programPath
|
2013-11-22 22:46:45 +00:00
|
|
|
where
|
|
|
|
go Nothing = debug [ "cannot determine program path" ]
|
|
|
|
go (Just program) = do
|
|
|
|
mvar <- liftIO $ newMVar InStartupScan
|
2013-11-23 03:12:06 +00:00
|
|
|
changed <- Just <$> asIO2 (changedFile urlrenderer mvar program)
|
2013-11-22 22:46:45 +00:00
|
|
|
let hooks = mkWatchHooks
|
|
|
|
{ addHook = changed
|
|
|
|
, addSymlinkHook = changed
|
|
|
|
, modifyHook = changed
|
|
|
|
, delDirHook = changed
|
|
|
|
}
|
|
|
|
let dir = parentDir program
|
|
|
|
let depth = length (splitPath dir) + 1
|
|
|
|
let nosubdirs f = length (splitPath f) == depth
|
|
|
|
void $ liftIO $ watchDir dir nosubdirs hooks (startup mvar)
|
|
|
|
-- Ignore bogus events generated during the startup scan.
|
|
|
|
startup mvar scanner = do
|
|
|
|
r <- scanner
|
|
|
|
void $ swapMVar mvar Started
|
|
|
|
return r
|
|
|
|
|
2013-11-23 03:12:06 +00:00
|
|
|
changedFile :: UrlRenderer -> MVar WatcherState -> FilePath -> FilePath -> Maybe FileStatus -> Assistant ()
|
|
|
|
changedFile urlrenderer mvar program file _status
|
|
|
|
| program /= file = noop
|
|
|
|
| otherwise = do
|
2013-11-22 22:46:45 +00:00
|
|
|
state <- liftIO $ readMVar mvar
|
2013-11-23 03:12:06 +00:00
|
|
|
when (state == Started) $ do
|
|
|
|
setstate Upgrading
|
|
|
|
ifM (sanityCheck program)
|
|
|
|
( handleUpgrade urlrenderer
|
|
|
|
, do
|
|
|
|
debug ["new version of", program, "failed sanity check; not using"]
|
|
|
|
setstate Started
|
|
|
|
)
|
|
|
|
where
|
|
|
|
setstate = void . liftIO . swapMVar mvar
|
|
|
|
|
|
|
|
{- The program's file has been changed. Before restarting,
|
|
|
|
- it needs to not be open for write by anything, and should run
|
|
|
|
- successfully when run with the parameter "version".
|
|
|
|
-}
|
|
|
|
sanityCheck :: FilePath -> Assistant Bool
|
|
|
|
sanityCheck program = do
|
|
|
|
whileM (liftIO haswriter) $ do
|
|
|
|
debug [program, "is still being written; waiting"]
|
|
|
|
liftIO $ threadDelaySeconds (Seconds 60)
|
|
|
|
debug [program, "has changed, and seems to be ready to run"]
|
|
|
|
liftIO $ boolSystem program [Param "version"]
|
|
|
|
where
|
|
|
|
haswriter = not . null
|
|
|
|
. filter (`elem` [Lsof.OpenReadWrite, Lsof.OpenWriteOnly])
|
|
|
|
. map snd3
|
|
|
|
<$> Lsof.query [program]
|
|
|
|
|
|
|
|
handleUpgrade :: UrlRenderer -> Assistant ()
|
|
|
|
handleUpgrade urlrenderer = do
|
|
|
|
#ifdef WITH_WEBAPP
|
|
|
|
button <- mkAlertButton True (T.pack "Finish Upgrade") urlrenderer ConfigFinishUpgradeR
|
|
|
|
void $ addAlert (upgradeReadyAlert button)
|
|
|
|
#else
|
|
|
|
noop
|
|
|
|
#endif
|