2013-11-23 04:54:08 +00:00
|
|
|
{- git-annex assistant upgrading
|
|
|
|
-
|
|
|
|
- Copyright 2013 Joey Hess <joey@kitenet.net>
|
|
|
|
-
|
|
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
|
|
|
module Assistant.Upgrade where
|
|
|
|
|
|
|
|
import Assistant.Common
|
2013-11-23 19:50:17 +00:00
|
|
|
import Assistant.Restart
|
2013-11-23 04:54:08 +00:00
|
|
|
import qualified Annex
|
|
|
|
import Assistant.Alert
|
|
|
|
import Assistant.DaemonStatus
|
2013-11-23 16:39:36 +00:00
|
|
|
import Utility.Env
|
global webapp redirects, to finish upgrades
When an automatic upgrade completes, or when the user clicks on the upgrade
button in one webapp, but also has it open in another browser window/tab,
we have a problem: The current web server is going to stop running in
minutes, but there is no way to send a redirect to the web browser to the
new url.
To solve this, used long polling, so the webapp is always listening for
urls it should redirect to. This allows globally redirecting every open
webapp. Works great! Tested with 2 web browsers with 2 tabs each.
May be useful for other purposes later too, dunno.
The overhead is 2 http requests per page load in the webapp. Due to yesod's
speed, this does not seem to noticibly delay it. Only 1 of the requests
could possibly block the page load, the other is async.
2013-11-23 18:47:38 +00:00
|
|
|
import Types.Distribution
|
2013-11-24 01:58:39 +00:00
|
|
|
import Logs.Transfer
|
|
|
|
import Logs.Web
|
|
|
|
import Annex.Content
|
|
|
|
import qualified Backend
|
|
|
|
import qualified Types.Backend
|
|
|
|
import qualified Types.Key
|
2013-11-24 02:12:36 +00:00
|
|
|
import Assistant.TransferQueue
|
|
|
|
import Assistant.TransferSlots
|
|
|
|
import Remote
|
|
|
|
|
|
|
|
import qualified Data.Map as M
|
2013-11-23 04:54:08 +00:00
|
|
|
|
2013-11-23 19:50:17 +00:00
|
|
|
{- Upgrade without interaction in the webapp. -}
|
|
|
|
unattendedUpgrade :: Assistant ()
|
|
|
|
unattendedUpgrade = do
|
|
|
|
prepUpgrade
|
|
|
|
url <- runRestart
|
|
|
|
postUpgrade url
|
2013-11-23 04:54:08 +00:00
|
|
|
|
|
|
|
prepUpgrade :: Assistant ()
|
|
|
|
prepUpgrade = do
|
|
|
|
void $ addAlert upgradingAlert
|
2013-11-23 16:39:36 +00:00
|
|
|
void $ liftIO $ setEnv upgradedEnv "1" True
|
2013-11-23 19:50:17 +00:00
|
|
|
prepRestart
|
2013-11-23 04:54:08 +00:00
|
|
|
|
global webapp redirects, to finish upgrades
When an automatic upgrade completes, or when the user clicks on the upgrade
button in one webapp, but also has it open in another browser window/tab,
we have a problem: The current web server is going to stop running in
minutes, but there is no way to send a redirect to the web browser to the
new url.
To solve this, used long polling, so the webapp is always listening for
urls it should redirect to. This allows globally redirecting every open
webapp. Works great! Tested with 2 web browsers with 2 tabs each.
May be useful for other purposes later too, dunno.
The overhead is 2 http requests per page load in the webapp. Due to yesod's
speed, this does not seem to noticibly delay it. Only 1 of the requests
could possibly block the page load, the other is async.
2013-11-23 18:47:38 +00:00
|
|
|
postUpgrade :: URLString -> Assistant ()
|
2013-11-23 19:50:17 +00:00
|
|
|
postUpgrade = postRestart
|
global webapp redirects, to finish upgrades
When an automatic upgrade completes, or when the user clicks on the upgrade
button in one webapp, but also has it open in another browser window/tab,
we have a problem: The current web server is going to stop running in
minutes, but there is no way to send a redirect to the web browser to the
new url.
To solve this, used long polling, so the webapp is always listening for
urls it should redirect to. This allows globally redirecting every open
webapp. Works great! Tested with 2 web browsers with 2 tabs each.
May be useful for other purposes later too, dunno.
The overhead is 2 http requests per page load in the webapp. Due to yesod's
speed, this does not seem to noticibly delay it. Only 1 of the requests
could possibly block the page load, the other is async.
2013-11-23 18:47:38 +00:00
|
|
|
|
|
|
|
autoUpgradeEnabled :: Assistant Bool
|
|
|
|
autoUpgradeEnabled = liftAnnex $ (==) AutoUpgrade . annexAutoUpgrade <$> Annex.getGitConfig
|
|
|
|
|
|
|
|
checkSuccessfulUpgrade :: IO Bool
|
|
|
|
checkSuccessfulUpgrade = isJust <$> getEnv upgradedEnv
|
|
|
|
|
|
|
|
upgradedEnv :: String
|
|
|
|
upgradedEnv = "GIT_ANNEX_UPGRADED"
|
2013-11-24 01:58:39 +00:00
|
|
|
|
2013-11-24 02:12:36 +00:00
|
|
|
{- Start downloading the distribution key from the web.
|
|
|
|
- Install a hook that will be run once the download is complete. -}
|
|
|
|
startDistributionDownload :: GitAnnexDistribution -> Assistant ()
|
|
|
|
startDistributionDownload d = do
|
|
|
|
liftAnnex $ setUrlPresent k u
|
|
|
|
hook <- asIO1 $ distributionDownloadComplete d
|
|
|
|
modifyDaemonStatus_ $ \status -> status
|
|
|
|
{ transferHook = M.insert k hook (transferHook status) }
|
|
|
|
maybe noop (queueTransfer "upgrade" Next (Just f) t)
|
|
|
|
=<< liftAnnex (remoteFromUUID webUUID)
|
|
|
|
startTransfer t
|
|
|
|
where
|
|
|
|
k = distributionKey d
|
|
|
|
u = distributionUrl d
|
|
|
|
f = takeFileName u ++ " (for upgrade)"
|
|
|
|
t = Transfer
|
|
|
|
{ transferDirection = Download
|
|
|
|
, transferUUID = webUUID
|
|
|
|
, transferKey = k
|
|
|
|
}
|
|
|
|
|
2013-11-24 01:58:39 +00:00
|
|
|
{- Fsck the key to verify the download. -}
|
|
|
|
distributionDownloadComplete :: GitAnnexDistribution -> Transfer -> Assistant ()
|
|
|
|
distributionDownloadComplete d t
|
|
|
|
| transferDirection t == Download = do
|
|
|
|
maybe noop upgradeToDistribution
|
|
|
|
=<< liftAnnex (withObjectLoc k fsckit (getM fsckit))
|
|
|
|
liftAnnex $ setUrlMissing k (distributionUrl d)
|
|
|
|
| otherwise = noop
|
|
|
|
where
|
|
|
|
k = distributionKey d
|
|
|
|
fsckit f = case Backend.maybeLookupBackendName (Types.Key.keyBackendName k) of
|
|
|
|
Nothing -> return $ Just f
|
|
|
|
Just b -> case Types.Backend.fsckKey b of
|
|
|
|
Nothing -> return $ Just f
|
|
|
|
Just a -> ifM (a k f)
|
|
|
|
( return $ Just f
|
|
|
|
, do
|
|
|
|
-- unlikely to resume a bad
|
|
|
|
-- download from web
|
|
|
|
liftIO $ nukeFile f
|
|
|
|
return Nothing
|
|
|
|
)
|
|
|
|
|
|
|
|
upgradeToDistribution :: FilePath -> Assistant ()
|
|
|
|
upgradeToDistribution f = error "TODO"
|