diff options
author | Joey Hess <joeyh@joeyh.name> | 2015-01-28 13:47:41 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2015-01-28 13:50:02 -0400 |
commit | f351b887265f0abce8d52ffcb7b9b2ee7bd8bc81 (patch) | |
tree | c7cb719e91b82bee7f4ea8e74732dd3f3d4dc103 | |
parent | 6a8efb186432cd9b8fa7a61f8129303f5bcc9e1f (diff) |
rework Differences data type
Eliminated complexity and future proofed. The most important change is that
all functions over Difference are now total; any Difference that can be
expressed should be handled. Avoids needs for sanity checking of inputs,
and version skew with the future.
Also, the difference.log now serializes a [Difference], not a Differences.
This saves space and keeps it simpler.
Note that [Difference] might contain conflicting differences (eg,
[Version5, Version6]. In this case, one of them needs to consistently win
over the others, probably based on Ord.
-rw-r--r-- | Annex/Difference.hs | 4 | ||||
-rw-r--r-- | Locations.hs | 2 | ||||
-rw-r--r-- | Logs/Difference.hs | 3 | ||||
-rw-r--r-- | Logs/Difference/Pure.hs | 2 | ||||
-rw-r--r-- | Types/Difference.hs | 97 | ||||
-rw-r--r-- | doc/git-annex.mdwn | 2 | ||||
-rw-r--r-- | doc/internals.mdwn | 2 | ||||
-rw-r--r-- | doc/tuning.mdwn | 20 |
8 files changed, 42 insertions, 90 deletions
diff --git a/Annex/Difference.hs b/Annex/Difference.hs index cb363e80c..07789e7bb 100644 --- a/Annex/Difference.hs +++ b/Annex/Difference.hs @@ -31,9 +31,7 @@ import qualified Data.Map as M setDifferences :: Annex () setDifferences = do u <- getUUID - otherds <- either error return - =<< sanityCheckDifferences . allDifferences - <$> recordedDifferences + otherds <- allDifferences <$> recordedDifferences ds <- mappend otherds . annexDifferences <$> Annex.getGitConfig when (ds /= mempty) $ do ds'@(Differences l) <- ifM (isJust <$> getVersion) diff --git a/Locations.hs b/Locations.hs index dcbde4bd9..ed0962230 100644 --- a/Locations.hs +++ b/Locations.hs @@ -135,7 +135,7 @@ gitAnnexLocation' key r config crippled -} | Git.repoIsLocalBare r || crippled - || hasDifference (== ObjectHashLower True) (annexDifferences config) = + || hasDifference (== ObjectHashLower) (annexDifferences config) = check $ map inrepo $ annexLocations key {- Non-bare repositories only use hashDirMixed, so - don't need to do any work to check if the file is diff --git a/Logs/Difference.hs b/Logs/Difference.hs index 68d624f99..fcebffee9 100644 --- a/Logs/Difference.hs +++ b/Logs/Difference.hs @@ -24,10 +24,11 @@ import Logs.UUIDBased import Logs.Difference.Pure recordDifferences :: Differences -> UUID -> Annex () -recordDifferences differences uuid = do +recordDifferences (Differences differences) uuid = do ts <- liftIO getPOSIXTime Annex.Branch.change differenceLog $ showLog id . changeLog ts uuid (show differences) . parseLog Just +recordDifferences UnknownDifferences _ = return () -- Map of UUIDs that have Differences recorded. -- If a new version of git-annex has added a Difference this version diff --git a/Logs/Difference/Pure.hs b/Logs/Difference/Pure.hs index 76d995a01..bbd4d348d 100644 --- a/Logs/Difference/Pure.hs +++ b/Logs/Difference/Pure.hs @@ -19,7 +19,7 @@ import Logs.UUIDBased parseDifferencesLog :: String -> (M.Map UUID Differences) parseDifferencesLog = simpleMap - . parseLog (Just . fromMaybe UnknownDifferences . readish) + . parseLog (Just . maybe UnknownDifferences Differences . readish) -- The sum of all recorded differences, across all UUIDs. allDifferences :: M.Map UUID Differences -> Differences diff --git a/Types/Difference.hs b/Types/Difference.hs index 7d0c28224..f92a30736 100644 --- a/Types/Difference.hs +++ b/Types/Difference.hs @@ -9,123 +9,74 @@ module Types.Difference ( Difference(..), Differences(..), getDifferences, - sanityCheckDifferences, differenceConfigKey, differenceConfigVal, hasDifference, ) where -import Utility.PartialPrelude import qualified Git import qualified Git.Config import Data.List import Data.Maybe import Data.Monoid -import Control.Applicative -- Describes differences from the v5 repository format. -- --- The serilization is stored in difference.log, so avoid changes that +-- The serialization is stored in difference.log, so avoid changes that -- would break compatability. -- --- Not breaking comparability is why a list of Differences is used, rather +-- Not breaking compatability is why a list of Differences is used, rather -- than a sum type. With a sum type, adding a new field for some future -- difference would serialize to a value that an older version could not -- parse, even if that new field was not used. With the Differences list, -- old versions can still parse it, unless the new Difference constructor -- is used. +-- +-- The constructors intentionally do not have parameters; this is to +-- ensure that any Difference that can be expressed is supported. +-- So, a new repository version would be Version6, rather than Version Int. data Difference - = Version Int - | ObjectHashLower Bool - | ObjectHashDirectories Int - | BranchHashDirectories Int - deriving (Show, Read, Ord) - -instance Eq Difference where - Version a == Version b = a == b - ObjectHashLower a == ObjectHashLower b = a == b - ObjectHashDirectories a == ObjectHashDirectories b = a == b - BranchHashDirectories a == BranchHashDirectories b = a == b - _ == _ = False + = ObjectHashLower + | OneLevelObjectHash + | OneLevelBranchHash + deriving (Show, Read, Ord, Eq, Enum, Bounded) data Differences = Differences [Difference] | UnknownDifferences - deriving (Show, Read, Ord) instance Eq Differences where - Differences a == Differences b = simplify (defver:a) == simplify (defver:b) - _ == _ = False + Differences a == Differences b = canon a == canon b + _ == _ = False -- UnknownDifferences cannot be equal instance Monoid Differences where mempty = Differences [] - mappend (Differences l1) (Differences l2) = Differences (simplify (l1 ++ l2)) + mappend (Differences l1) (Differences l2) = Differences (canon (l1 ++ l2)) mappend _ _ = UnknownDifferences --- This is the default repository version that is assumed when no other one --- is given. Note that [] == [Version 5] -defver :: Difference -defver = Version 5 - --- Given [Version 6, Version 5], returns [Version 6] -simplify :: [Difference] -> [Difference] -simplify = go . sort - where - go [] = [] - go (d:[]) = [d] - go (d1:d2:ds) - | like d1 d2 = go (d2:ds) - | otherwise = d1 : go (d2:ds) - - like (Version _) (Version _) = True - like _ _ = False +canon :: [Difference] -> [Difference] +canon = nub . sort getDifferences :: Git.Repo -> Differences -getDifferences r = checksane $ Differences $ catMaybes - [ ObjectHashLower - <$> getmaybebool (differenceConfigKey (ObjectHashLower undefined)) - , ObjectHashDirectories - <$> getmayberead (differenceConfigKey (ObjectHashDirectories undefined)) - , BranchHashDirectories - <$> getmayberead (differenceConfigKey (BranchHashDirectories undefined)) - ] +getDifferences r = Differences $ catMaybes $ + map getmaybe [minBound .. maxBound] where - getmaybe k = Git.Config.getMaybe k r - getmayberead k = readish =<< getmaybe k - getmaybebool k = Git.Config.isTrue =<< getmaybe k - checksane = either error id . sanityCheckDifferences + getmaybe d = case Git.Config.isTrue =<< Git.Config.getMaybe (differenceConfigKey d) r of + Just True -> Just d + _ -> Nothing differenceConfigKey :: Difference -> String -differenceConfigKey (Version _) = "annex.version" -differenceConfigKey (ObjectHashLower _) = tunable "objecthashlower" -differenceConfigKey (ObjectHashDirectories _) = tunable "objecthashdirectories" -differenceConfigKey (BranchHashDirectories _) = tunable "branchhashdirectories" +differenceConfigKey ObjectHashLower = tunable "objecthashlower" +differenceConfigKey OneLevelObjectHash = tunable "objecthash1" +differenceConfigKey OneLevelBranchHash = tunable "branchhash1" differenceConfigVal :: Difference -> String -differenceConfigVal (Version v) = show v -differenceConfigVal (ObjectHashLower b) = Git.Config.boolConfig b -differenceConfigVal (ObjectHashDirectories n) = show n -differenceConfigVal (BranchHashDirectories n) = show n +differenceConfigVal _ = Git.Config.boolConfig True tunable :: String -> String tunable k = "annex.tune." ++ k -sanityCheckDifferences :: Differences -> Either String Differences -sanityCheckDifferences d@(Differences l) - | null problems = Right d - | otherwise = Left (intercalate "; " problems) - where - problems = catMaybes (map check l) - check (ObjectHashDirectories n) - | n == 1 || n == 2 = Nothing - | otherwise = Just $ "Bad value for objecthashdirectories -- should be 1 or 2, not " ++ show n - check (BranchHashDirectories n) - | n == 1 || n == 2 = Nothing - | otherwise = Just $ "Bad value for branhhashdirectories -- should be 1 or 2, not " ++ show n - check _ = Nothing -sanityCheckDifferences UnknownDifferences = Left "unknown differences detected; update git-annex" - hasDifference :: (Difference -> Bool) -> Differences -> Bool hasDifference f (Differences l) = any f l hasDifference _ UnknownDifferences = False diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn index 06eb85e11..80dce0ddc 100644 --- a/doc/git-annex.mdwn +++ b/doc/git-annex.mdwn @@ -1839,7 +1839,7 @@ Here are all the supported configuration settings. Used by hook special remotes and external special remotes to record the type of the remote. -* `annex.tune.objecthashdirectories`, `annex.tune.objecthashlower`, `annex.tune.branchhashdirectories` +* `annex.tune.objecthash1`, `annex.tune.objecthashlower`, `annex.tune.branchhash1` These can be passed to `git annex init` to tune the repository. They cannot be safely changed in a running repository. diff --git a/doc/internals.mdwn b/doc/internals.mdwn index 4eb72ceac..a562d6067 100644 --- a/doc/internals.mdwn +++ b/doc/internals.mdwn @@ -265,4 +265,4 @@ that should prevent merging. Example: - e605dca6-446a-11e0-8b2a-002170d25c55 [Version 5] timestamp=1422387398.30395s + e605dca6-446a-11e0-8b2a-002170d25c55 [ObjectHashLower] timestamp=1422387398.30395s diff --git a/doc/tuning.mdwn b/doc/tuning.mdwn index 761071b6b..cbe0eca64 100644 --- a/doc/tuning.mdwn +++ b/doc/tuning.mdwn @@ -12,7 +12,7 @@ done by passing `-c name=value` parameters to `git annex init`. For example, this will make git-annex use only 1 level for hash directories in `.git/annex/objects`: - git -c annex.tune.objecthashdirectories=1 annex init + git -c annex.tune.objecthash1=true annex init It's very important to keep in mind that this makes a nonstandard format git-annex repository. In general, this cannot safely be used with @@ -29,16 +29,18 @@ Again, tuned repositories are an experimental feature; use with caution! The following tuning parameters are available: -* `annex.tune.objecthashdirectories` (default: 2) - Sets the number of hash directories to use in `.git/annex/objects/` +* `annex.tune.objecthash1=true` + Use just one level of hash directories in `.git/annex/objects/`, + instead of the default two levels. -* `annex.tune.objecthashlower` (default: false) - Set to true to make the hash directories in `.git/annex/objects/` use - all lower-case. +* `annex.tune.objecthashlower=true` + Make the hash directories in `.git/annex/objects/` use + all lower-case, instead of the default mixed-case. -* `annex.tune.branchhashdirectories` (default: 2) - Sets the number of hash directories to use in the git-annex branch. +* `annex.tune.branchhash1=true` + Use just one level of hash directories in the git-annex branch, + instead of the default two levels. Note that git-annex will automatically propigate these setting to -`.git/config` for tuned repsitories. You should never directly change +`.git/config` for tuned repositories. You should never directly change these settings in `.git/config` |