watch git-annex program file to detect upgrades

Not yet wired up to restart the assistant on upgrade; that needs careful
sanity checking to wait until the upgrade is done before restarting.

Used the DirWatcher here, so it gets events for any changes to the
directory containing the program file. (But not subdirs.) This is necessary
in order to detect when the file is renamed as part of the upgrade, which
an inotify on a single file would not detect. (Also, I have DirWatcher code,
but not FileWatcher code.)

Note that upgrades that remove or rename a whole directory tree containing
the executable will *not* trigger this code. So eg, deleting and replacing
the whole standalone tarball dir tree won't work -- but untarring it
over top will. So should dpkg package upgrades.

Added programPath, using a new GHC feature to find the full path to the
executable. The fallback code for old GHC or unsupported OS is less good;
its worst failure mode would be either failing to find the program, and so
not checking for upgrades, or finding a git-annex that's in PATH, but is
not the one running.

This commit was sponsored by John Roepke.
This commit is contained in:
Joey Hess 2013-11-22 18:46:45 -04:00
parent f8a3dd9c3d
commit 766c31c95c
5 changed files with 81 additions and 1 deletions

View file

@ -29,6 +29,7 @@ import Assistant.Threads.MountWatcher
#endif
import Assistant.Threads.NetWatcher
import Assistant.Threads.Upgrader
import Assistant.Threads.UpgradeWatcher
import Assistant.Threads.TransferScanner
import Assistant.Threads.TransferPoller
import Assistant.Threads.ConfigMonitor
@ -152,6 +153,7 @@ startDaemon assistant foreground startdelay cannotrun listenhost startbrowser =
#endif
, assist $ netWatcherThread
, assist $ upgraderThread urlrenderer
, assist $ upgradWatcherThread
, assist $ netWatcherFallbackThread
, assist $ transferScannerThread urlrenderer
, assist $ cronnerThread urlrenderer

View file

@ -0,0 +1,51 @@
{- 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.
-}
module Assistant.Threads.UpgradeWatcher (
upgradWatcherThread
) where
import Assistant.Common
import Utility.DirWatcher
import Utility.DirWatcher.Types
import Config.Files
import Control.Concurrent.MVar
data WatcherState = InStartupScan | Started | Upgrading
deriving (Eq)
upgradWatcherThread :: NamedThread
upgradWatcherThread = namedThread "UpgradeWatcher" $ go =<< liftIO programPath
where
go Nothing = debug [ "cannot determine program path" ]
go (Just program) = do
mvar <- liftIO $ newMVar InStartupScan
changed <- Just <$> asIO2 (changedFile mvar program)
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
changedFile :: MVar WatcherState -> FilePath -> FilePath -> Maybe FileStatus -> Assistant ()
changedFile mvar program file _status
| program == file = do
state <- liftIO $ readMVar mvar
when (state == Started) $
debug [ "saw change to", file ]
| otherwise = noop

View file

@ -1,4 +1,4 @@
{- git-annex assistant thread to detect when upgrade is needed
{- git-annex assistant thread to detect when upgrade is available
-
- Copyright 2013 Joey Hess <joey@kitenet.net>
-

View file

@ -5,11 +5,14 @@
- Licensed under the GNU GPL version 3 or higher.
-}
{-# LANGUAGE CPP #-}
module Config.Files where
import Common
import Utility.Tmp
import Utility.FreeDesktop
import System.Environment
{- ~/.config/git-annex/file -}
userConfigFile :: FilePath -> IO FilePath
@ -67,3 +70,23 @@ readProgramFile = do
)
where
cmd = "git-annex"
{- A fully qualified path to the currently running git-annex program.
-
- getExecutablePath is available since ghc 7.4.2. On OSs it supports
- well, it returns the complete path to the program. But, on other OSs,
- it might return just the basename.
-}
programPath :: IO (Maybe FilePath)
programPath = do
#if MIN_VERSION_base(4,6,0)
exe <- getExecutablePath
p <- if isAbsolute exe
then return exe
else readProgramFile
#else
p <- readProgramFile
#endif
-- In case readProgramFile returned just the command name,
-- fall back to finding it in PATH.
searchPath p

4
debian/changelog vendored
View file

@ -5,6 +5,10 @@ git-annex (5.20131121) UNRELEASED; urgency=low
* webapp: Detect when an upgrade to git-annex is available.
(Only when git-annex is installed using the prebuilt binaries
from git-annex upstream, not from eg Debian.)
* assistant: Detect when the git-annex binary is modified or replaced,
and either prompt the user to restart the program, or automatically
restart it.
* annex.autoupgrade configures both the above upgrade behaviors.
-- Joey Hess <joeyh@debian.org> Wed, 20 Nov 2013 18:30:47 -0400