import qualified Data.Map as M
defaultVersion :: RepoVersion
-defaultVersion = RepoVersion 8
+defaultVersion = RepoVersion 10
latestVersion :: RepoVersion
-latestVersion = RepoVersion 9
+latestVersion = RepoVersion 10
supportedVersions :: [RepoVersion]
-supportedVersions = map RepoVersion [8, 9]
+supportedVersions = map RepoVersion [8, 9, 10]
upgradeableVersions :: [RepoVersion]
#ifndef mingw32_HOST_OS
-upgradeableVersions = map RepoVersion [0..8]
+upgradeableVersions = map RepoVersion [0..10]
#else
-upgradeableVersions = map RepoVersion [2..8]
+upgradeableVersions = map RepoVersion [2..10]
#endif
autoUpgradeableVersions :: M.Map RepoVersion RepoVersion
, (RepoVersion 5, latestVersion)
, (RepoVersion 6, latestVersion)
, (RepoVersion 7, latestVersion)
+ , (RepoVersion 8, latestVersion)
+ , (RepoVersion 9, latestVersion)
]
versionField :: ConfigKey
versionNeedsWritableContentFiles :: Maybe RepoVersion -> Bool
versionNeedsWritableContentFiles (Just v)
- | v >= RepoVersion 9 = False
+ | v >= RepoVersion 10 = False
versionNeedsWritableContentFiles _ = True
--- /dev/null
+{- git-annex upgrade types
+ -
+ - Copyright 2022 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+module Types.Upgrade where
+
+data UpgradeResult = UpgradeSuccess | UpgradeFailed | UpgradeDeferred
{- git-annex upgrade support
-
- - Copyright 2010-2020 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2022 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
module Upgrade where
import Annex.Common
+import Types.Upgrade
import qualified Annex
import qualified Git
import Config
import qualified Upgrade.V6
import qualified Upgrade.V7
import qualified Upgrade.V8
+import qualified Upgrade.V9
import qualified Data.Map as M
upgrade :: Bool -> RepoVersion -> Annex Bool
upgrade automatic destversion = do
- upgraded <- go =<< getVersion
- when upgraded
- postupgrade
+ (upgraded, newversion) <- go =<< getVersion
+ when upgraded $
+ postupgrade newversion
return upgraded
where
go (Just v)
- | v >= destversion = return True
+ | v >= destversion = return (True, Just v)
| otherwise = ifM upgradingRemote
( upgraderemote
- , ifM (up v)
- ( go (Just (RepoVersion (fromRepoVersion v + 1)))
- , return False
- )
+ , up v >>= \case
+ UpgradeSuccess -> go (Just (incrversion v) )
+ UpgradeFailed -> return (False, Just v)
+ UpgradeDeferred -> return (True, Just v)
)
- go _ = return True
+ go Nothing = return (True, Nothing)
- postupgrade = ifM upgradingRemote
+ incrversion v = RepoVersion (fromRepoVersion v + 1)
+
+ postupgrade newversion = ifM upgradingRemote
( reloadConfig
- , setVersion destversion
+ , maybe noop setVersion newversion
)
#ifndef mingw32_HOST_OS
up (RepoVersion 6) = Upgrade.V6.upgrade automatic
up (RepoVersion 7) = Upgrade.V7.upgrade automatic
up (RepoVersion 8) = Upgrade.V8.upgrade automatic
- up _ = return True
+ up (RepoVersion 9) = Upgrade.V9.upgrade automatic
+ up _ = return UpgradeDeferred
-- Upgrade local remotes by running git-annex upgrade in them.
-- This avoids complicating the upgrade code by needing to handle
]
(\p -> p { cwd = Just rp })
(\_ _ _ pid -> waitForProcess pid >>= return . \case
- ExitSuccess -> True
- _ -> False
+ ExitSuccess -> (True, Nothing)
+ _ -> (False, Nothing)
)
upgradingRemote :: Annex Bool
module Upgrade.V0 where
import Annex.Common
+import Types.Upgrade
import Annex.Content
import qualified Upgrade.V1
-upgrade :: Annex Bool
+upgrade :: Annex UpgradeResult
upgrade = do
showAction "v0 to v1"
import qualified System.FilePath.ByteString as P
import Annex.Common
+import Types.Upgrade
import Annex.Content
import Annex.Link
import Annex.Perms
-- Something similar to the migrate subcommand could be used,
-- and users could then run that at their leisure.
-upgrade :: Annex Bool
+upgrade :: Annex UpgradeResult
upgrade = do
showAction "v1 to v2"
module Upgrade.V2 where
import Annex.Common
+import Types.Upgrade
import qualified Git
import qualified Git.Command
import qualified Git.Ref
- * Remove stuff that used to be needed in .gitattributes.
- * Commit changes.
-}
-upgrade :: Annex Bool
+upgrade :: Annex UpgradeResult
upgrade = do
showAction "v2 to v3"
bare <- fromRepo Git.repoIsLocalBare
unless bare push
- return True
+ return UpgradeSuccess
locationLogs :: Annex [(Key, FilePath)]
locationLogs = do
module Upgrade.V4 where
import Annex.Common
+import Types.Upgrade
{- Was only used for direct mode upgrade. v4 to v5 indirect update is a no-op,
- and direct mode is no longer supported, so nothing needs to be done. -}
-upgrade :: Bool -> Annex Bool
-upgrade _automatic = return True
+upgrade :: Bool -> Annex UpgradeResult
+upgrade _automatic = return UpgradeSuccess
module Upgrade.V5 where
import Annex.Common
+import Types.Upgrade
import Config
import Config.Smudge
import Annex.InodeSentinal
import qualified Data.ByteString as S
-upgrade :: Bool -> Annex Bool
+upgrade :: Bool -> Annex UpgradeResult
upgrade automatic = flip catchNonAsync onexception $ do
unless automatic $
showAction "v5 to v6"
-- use direct mode may not have created it.
unlessM isDirect $
createInodeSentinalFile True
- return True
+ return UpgradeSuccess
where
onexception e = do
warning $ "caught exception: " ++ show e
- return False
+ return UpgradeFailed
-- git before 2.22 would OOM running git status on a large file.
--
module Upgrade.V6 where
import Annex.Common
+import Types.Upgrade
import Config
import Annex.Hook
-upgrade :: Bool -> Annex Bool
+upgrade :: Bool -> Annex UpgradeResult
upgrade automatic = do
unless automatic $
showAction "v6 to v7"
unlessM isBareRepo $ do
hookWrite postCheckoutHook
hookWrite postMergeHook
- return True
+ return UpgradeSuccess
import qualified Annex
import Annex.Common
+import Types.Upgrade
import Annex.CatFile
import qualified Database.Keys
import qualified Database.Keys.SQL
import qualified System.FilePath.ByteString as P
-upgrade :: Bool -> Annex Bool
+upgrade :: Bool -> Annex UpgradeResult
upgrade automatic = do
unless automatic $
showAction "v7 to v8"
updateSmudgeFilter
- return True
+ return UpgradeSuccess
gitAnnexKeysDbOld :: Git.Repo -> RawFilePath
gitAnnexKeysDbOld r = gitAnnexDir r P.</> "keys"
module Upgrade.V8 where
import Annex.Common
-import Annex.Content
-import Annex.Perms
-import Git.ConfigTypes
-import Types.RepoVersion
+import Types.Upgrade
+import Utility.Daemon
-upgrade :: Bool -> Annex Bool
+upgrade :: Bool -> Annex UpgradeResult
upgrade automatic = do
- unless automatic $
- showAction "v8 to v9"
+ -- Skip running when git-annex assistant (or watch) is running,
+ -- because these are long-running daemons that could conceivably
+ -- run for an entire year, and so still be running when the v10
+ -- upgrade happens. If the assistant then tried to drop a file
+ -- after the v10 upgrade, it would use the wrong content file
+ -- locking, which could lead to data loss. The remotedaemon does
+ -- not drop content, so will not block the upgrade.
+ pidfile <- fromRepo gitAnnexPidFile
+ liftIO (checkDaemon (fromRawFilePath pidfile)) >>= \case
+ Just _pid
+ | automatic -> return UpgradeDeferred
+ | otherwise -> giveup "Cannot upgrade to v9 when git-annex assistant or watch daemon is running."
+ Nothing -> do
+ unless automatic $
+ showAction "v8 to v9"
- {- When core.sharedRepository is set, object files
- - used to have their write bits set. That can now be removed,
- - if the user the upgrade is running as has permission to remove
- - it. (Otherwise, a later fsck will fix up the permissions.) -}
- withShared $ \sr -> case sr of
- GroupShared -> removewrite sr
- AllShared -> removewrite sr
- _ -> return ()
-
- return True
- where
- newver = Just (RepoVersion 9)
-
- removewrite sr = do
- ks <- listKeys InAnnex
- forM_ ks $ \k -> do
- obj <- calcRepo (gitAnnexLocation k)
- keystatus <- getKeyStatus k
- case keystatus of
- KeyPresent -> void $ tryIO $
- freezeContent'' sr obj newver
- KeyUnlockedThin -> return ()
- KeyLockedThin -> return ()
- KeyMissing -> return ()
+ return UpgradeSuccess
--- /dev/null
+{- git-annex v9 -> v10 upgrade support
+ -
+ - Copyright 2022 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+module Upgrade.V9 where
+
+import Annex.Common
+import Types.Upgrade
+import Annex.Content
+import Annex.Perms
+import Git.ConfigTypes
+import Types.RepoVersion
+
+upgrade :: Bool -> Annex UpgradeResult
+upgrade automatic = do
+ unless automatic $
+ showAction "v9 to v10"
+
+ {- When core.sharedRepository is set, object files
+ - used to have their write bits set. That can now be removed,
+ - if the user the upgrade is running as has permission to remove
+ - it. (Otherwise, a later fsck will fix up the permissions.) -}
+ withShared $ \sr -> case sr of
+ GroupShared -> removewrite sr
+ AllShared -> removewrite sr
+ _ -> return ()
+
+ return UpgradeDeferred
+ where
+ newver = Just (RepoVersion 9)
+
+ removewrite sr = do
+ ks <- listKeys InAnnex
+ forM_ ks $ \k -> do
+ obj <- calcRepo (gitAnnexLocation k)
+ keystatus <- getKeyStatus k
+ case keystatus of
+ KeyPresent -> void $ tryIO $
+ freezeContent'' sr obj newver
+ KeyUnlockedThin -> return ()
+ KeyLockedThin -> return ()
+ KeyMissing -> return ()
The upgrade events, so far:
+## v9 -> v10 (git-annex version 10.x)
+
+v10 repositories change a fundamental part of how git-annex does locking.
+
+v9 repositories are automatically upgraded to v10, but with a delay.
+The upgrade happens one year after the repository was upgraded to v9.
+This delay is because it would not be safe to upgrade to v10 if a
+git-annex process version 8.x was still running. Waiting a year makes
+it very unlikely that such a process is still running.
+
+## v8 -> v9 (git-annex version 10.x)
+
+v8 repositories are automatically upgraded to v9.
+
+Starting in v9, upgrades to a repository are prevented while another
+git-annex command is running. That is needed for the v10 repository
+upgrade to be performed safely.
+
## v7 -> v8 (git-annex version 8.x)
v7 repositories are automatically upgraded to v8.
Types.Transitions
Types.TrustLevel
Types.UUID
+ Types.Upgrade
Types.UrlContents
Types.VectorClock
Types.View
Upgrade.V6
Upgrade.V7
Upgrade.V8
+ Upgrade.V9
Utility.Aeson
Utility.Android
Utility.Applicative