a new Key data type with metadata
This commit is contained in:
parent
0e0f85e09d
commit
fe09c2b723
2 changed files with 90 additions and 1 deletions
88
Key.hs
Normal file
88
Key.hs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
{- git-annex Key data type
|
||||||
|
-
|
||||||
|
- Copyright 2011 Joey Hess <joey@kitenet.net>
|
||||||
|
-
|
||||||
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
|
-}
|
||||||
|
|
||||||
|
module Key where
|
||||||
|
|
||||||
|
import Data.String.Utils
|
||||||
|
import Test.QuickCheck
|
||||||
|
import Data.Maybe
|
||||||
|
import Data.List
|
||||||
|
|
||||||
|
{- A Key has a unique name, is associated with a backend,
|
||||||
|
- and may contain other metadata. -}
|
||||||
|
data Field = KeyName | KeyBackend | KeySize | KeyModTime
|
||||||
|
deriving (Eq, Ord, Show)
|
||||||
|
newtype Key = Key [(Field, String)]
|
||||||
|
deriving (Eq, Ord)
|
||||||
|
|
||||||
|
{- Generates a Key given a name, a backend and a list of other metadata. -}
|
||||||
|
keyGen :: String -> String -> [(Field, String)] -> Key
|
||||||
|
keyGen name backend meta = Key $ (KeyName, name):(KeyBackend, backend):meta
|
||||||
|
|
||||||
|
{- Gets the name of a Key. -}
|
||||||
|
keyName :: Key -> String
|
||||||
|
keyName key = fromJust $ keyField key KeyName
|
||||||
|
|
||||||
|
{- Gets the backend associated with a Key. -}
|
||||||
|
keyBackend :: Key -> String
|
||||||
|
keyBackend key = fromJust $ keyField key KeyBackend
|
||||||
|
|
||||||
|
{- Looks up a given Field of a Key's metadata. -}
|
||||||
|
keyField :: Key -> Field -> Maybe String
|
||||||
|
keyField (Key meta) field =
|
||||||
|
if null matches
|
||||||
|
then Nothing
|
||||||
|
else Just $ snd $ head matches
|
||||||
|
where
|
||||||
|
matches = filter match meta
|
||||||
|
match (f, _) = f == field
|
||||||
|
|
||||||
|
fieldSep :: Char
|
||||||
|
fieldSep = ','
|
||||||
|
|
||||||
|
{- Keys show as strings that are suitable for use as filenames.
|
||||||
|
- The name field is always shown last, and is the only field
|
||||||
|
- allowed to contain the fieldSep. -}
|
||||||
|
instance Show Key where
|
||||||
|
show k@(Key meta) = join [fieldSep] $ map showp meta' ++ [name]
|
||||||
|
where
|
||||||
|
name = 'n':keyName k
|
||||||
|
meta' = sort $ (filter (\(f, _) -> f /= KeyName)) meta
|
||||||
|
showp (f, v) = (field f) : v
|
||||||
|
|
||||||
|
field KeyBackend = 'b'
|
||||||
|
field KeySize = 's'
|
||||||
|
field KeyModTime = 'm'
|
||||||
|
field f = error $ "unknown key field" ++ show f
|
||||||
|
|
||||||
|
instance Read Key where
|
||||||
|
readsPrec _ s = [(Key (meta s []), "")]
|
||||||
|
where
|
||||||
|
meta (c:r) m = findfield c r m
|
||||||
|
meta [] m = m
|
||||||
|
|
||||||
|
findfield 'n' v m = (KeyName, v):m -- rest is name
|
||||||
|
findfield c v m = let (v', _:r) = span (/= fieldSep) v in
|
||||||
|
meta r (field c v' m)
|
||||||
|
|
||||||
|
field 'b' v m = (KeyBackend, v):m
|
||||||
|
field 's' v m = (KeySize, v):m
|
||||||
|
field 'm' v m = (KeyModTime, v):m
|
||||||
|
field _ _ m = m -- just ignore unparseable fields
|
||||||
|
|
||||||
|
-- for quickcheck
|
||||||
|
instance Arbitrary Key where
|
||||||
|
arbitrary = do
|
||||||
|
backendname <- arbitrary
|
||||||
|
value <- arbitrary
|
||||||
|
return $ keyGen value backendname []
|
||||||
|
|
||||||
|
prop_idempotent_key_read_show :: Key -> Bool
|
||||||
|
prop_idempotent_key_read_show k
|
||||||
|
-- backend names will never contain the fieldSep
|
||||||
|
| fieldSep `elem` (keyBackend k) = True
|
||||||
|
| otherwise = k == (read $ show k)
|
3
test.hs
3
test.hs
|
@ -38,6 +38,7 @@ import qualified Trust
|
||||||
import qualified Remotes
|
import qualified Remotes
|
||||||
import qualified Content
|
import qualified Content
|
||||||
import qualified Command.DropUnused
|
import qualified Command.DropUnused
|
||||||
|
import qualified Key
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
@ -55,7 +56,7 @@ quickcheck :: Test
|
||||||
quickcheck = TestLabel "quickcheck" $ TestList
|
quickcheck = TestLabel "quickcheck" $ TestList
|
||||||
[ qctest "prop_idempotent_deencode" Git.prop_idempotent_deencode
|
[ qctest "prop_idempotent_deencode" Git.prop_idempotent_deencode
|
||||||
, qctest "prop_idempotent_fileKey" Locations.prop_idempotent_fileKey
|
, qctest "prop_idempotent_fileKey" Locations.prop_idempotent_fileKey
|
||||||
, qctest "prop_idempotent_key_read_show" BackendTypes.prop_idempotent_key_read_show
|
, qctest "prop_idempotent_key_read_show" Key.prop_idempotent_key_read_show
|
||||||
, qctest "prop_idempotent_shellEscape" Utility.prop_idempotent_shellEscape
|
, qctest "prop_idempotent_shellEscape" Utility.prop_idempotent_shellEscape
|
||||||
, qctest "prop_idempotent_shellEscape_multiword" Utility.prop_idempotent_shellEscape_multiword
|
, qctest "prop_idempotent_shellEscape_multiword" Utility.prop_idempotent_shellEscape_multiword
|
||||||
, qctest "prop_parentDir_basics" Utility.prop_parentDir_basics
|
, qctest "prop_parentDir_basics" Utility.prop_parentDir_basics
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue