diff options
-rw-r--r-- | Annex/FileMatcher.hs | 1 | ||||
-rw-r--r-- | CmdLine/GitAnnex/Options.hs | 2 | ||||
-rw-r--r-- | Command/MetaData.hs | 2 | ||||
-rw-r--r-- | Limit.hs | 12 | ||||
-rw-r--r-- | Types/MetaData.hs | 33 | ||||
-rw-r--r-- | debian/changelog | 5 | ||||
-rw-r--r-- | doc/git-annex.mdwn | 5 |
7 files changed, 49 insertions, 11 deletions
diff --git a/Annex/FileMatcher.hs b/Annex/FileMatcher.hs index f3f98fde6..750795280 100644 --- a/Annex/FileMatcher.hs +++ b/Annex/FileMatcher.hs @@ -83,6 +83,7 @@ parseToken checkpresent checkpreferreddir groupmap t , ("inbackend", limitInBackend) , ("largerthan", limitSize (>)) , ("smallerthan", limitSize (<)) + , ("metadata", limitMetaData) , ("inallgroup", limitInAllGroup groupmap) ] where diff --git a/CmdLine/GitAnnex/Options.hs b/CmdLine/GitAnnex/Options.hs index fcf5deaf0..f9f5989ee 100644 --- a/CmdLine/GitAnnex/Options.hs +++ b/CmdLine/GitAnnex/Options.hs @@ -54,6 +54,8 @@ gitAnnexOptions = commonOptions ++ "match files larger than a size" , Option [] ["smallerthan"] (ReqArg Limit.addSmallerThan paramSize) "match files smaller than a size" + , Option [] ["metadata"] (ReqArg Limit.addMetaData "FIELD=VALUE") + "match files with attached metadata" , Option [] ["want-get"] (NoArg Limit.Wanted.addWantGet) "match files the repository wants to get" , Option [] ["want-drop"] (NoArg Limit.Wanted.addWantDrop) diff --git a/Command/MetaData.hs b/Command/MetaData.hs index cc0364a30..5608701f1 100644 --- a/Command/MetaData.hs +++ b/Command/MetaData.hs @@ -21,7 +21,7 @@ def = [withOptions [setOption] $ command "metadata" paramPaths seek SectionUtility "sets metadata of a file"] setOption :: Option -setOption = Option ['s'] ["set"] (ReqArg mkmod "field[+-]=value") "set metadata" +setOption = Option ['s'] ["set"] (ReqArg mkmod "FIELD[+-]=VALUE") "set metadata" where mkmod p = case parseModMeta p of Left e -> error e @@ -23,6 +23,8 @@ import Types.Key import Types.Group import Types.FileMatcher import Types.Limit +import Types.MetaData +import Logs.MetaData import Logs.Group import Logs.Unused import Logs.Location @@ -262,6 +264,16 @@ limitSize vs s = case readSize dataUnits s of <$> getFileStatus (relFile fi) return $ filesize `vs` Just sz +addMetaData :: String -> Annex () +addMetaData = addLimit . limitMetaData + +limitMetaData :: MkLimit +limitMetaData s = case parseMetaData s of + Left e -> Left e + Right (f, v) -> Right $ const $ checkKey (check f v) + where + check f v k = S.member v . metaDataValues f <$> getCurrentMetaData k + addTimeLimit :: String -> Annex () addTimeLimit s = do let seconds = maybe (error "bad time-limit") durationToPOSIXTime $ diff --git a/Types/MetaData.hs b/Types/MetaData.hs index cd694e86a..151f456c0 100644 --- a/Types/MetaData.hs +++ b/Types/MetaData.hs @@ -28,10 +28,11 @@ module Types.MetaData ( differenceMetaData, currentMetaData, currentMetaDataValues, - getAllMetaData, + metaDataValues, ModMeta(..), modMeta, parseModMeta, + parseMetaData, prop_metadata_sane, prop_metadata_serialize ) where @@ -170,7 +171,7 @@ isSet (MetaValue (CurrentlySet isset) _) = isset {- Gets only currently set values -} currentMetaDataValues :: MetaField -> MetaData -> S.Set MetaValue -currentMetaDataValues f m = S.filter isSet (getAllMetaData f m) +currentMetaDataValues f m = S.filter isSet (metaDataValues f m) currentMetaData :: MetaData -> MetaData currentMetaData (MetaData m) = removeEmptyFields $ MetaData $ @@ -180,8 +181,8 @@ removeEmptyFields :: MetaData -> MetaData removeEmptyFields (MetaData m) = MetaData $ M.filter (not . S.null) m {- Gets currently set values, but also values that have been unset. -} -getAllMetaData :: MetaField -> MetaData -> S.Set MetaValue -getAllMetaData f (MetaData m) = fromMaybe S.empty (M.lookup f m) +metaDataValues :: MetaField -> MetaData -> S.Set MetaValue +metaDataValues f (MetaData m) = fromMaybe S.empty (M.lookup f m) {- Ways that existing metadata can be modified -} data ModMeta @@ -202,15 +203,27 @@ modMeta m (SetMeta f v) = updateMetaData f v $ {- Parses field=value, field+=value, field-=value -} parseModMeta :: String -> Either String ModMeta parseModMeta p = case lastMaybe f of - Just '+' -> AddMeta <$> mkf f' <*> v - Just '-' -> DelMeta <$> mkf f' <*> v - _ -> SetMeta <$> mkf f <*> v + Just '+' -> AddMeta <$> mkMetaField f' <*> v + Just '-' -> DelMeta <$> mkMetaField f' <*> v + _ -> SetMeta <$> mkMetaField f <*> v where (f, sv) = separate (== '=') p f' = beginning f v = pure (toMetaValue sv) - mkf fld = maybe (Left $ badfield fld) Right (toMetaField fld) - badfield fld = "Illegal metadata field name, \"" ++ fld ++ "\"" + +{- Parses field=value -} +parseMetaData :: String -> Either String (MetaField, MetaValue) +parseMetaData p = (,) + <$> mkMetaField f + <*> pure (toMetaValue v) + where + (f, v) = separate (== '=') p + +mkMetaField :: String -> Either String MetaField +mkMetaField f = maybe (Left $ badField f) Right (toMetaField f) + +badField :: String -> String +badField f = "Illegal metadata field name, \"" ++ f ++ "\"" {- Avoid putting too many fields in the map; extremely large maps make - the seriaization test slow due to the sheer amount of data. @@ -228,7 +241,7 @@ instance Arbitrary MetaField where prop_metadata_sane :: MetaData -> MetaField -> MetaValue -> Bool prop_metadata_sane m f v = and - [ S.member v $ getAllMetaData f m' + [ S.member v $ metaDataValues f m' , not (isSet v) || S.member v (currentMetaDataValues f m') , differenceMetaData m' newMetaData == m' ] diff --git a/debian/changelog b/debian/changelog index f8d739164..f6d2dffad 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,10 @@ git-annex (5.20140211) UNRELEASED; urgency=medium + * metadata: New command that can attach metadata to files. + * --metadata can be used to limit commands to acting on files + that have particular metadata. + * Preferred content expressions can use metadata=field=value + to limit them to acting on files that have particular metadata. * Add progress display for transfers to/from external special remotes. * Windows webapp: Can set up box.com, Amazon S3 remotes. * Windows webapp: Can create repos on removable drives. diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn index e0028d2d6..39577190f 100644 --- a/doc/git-annex.mdwn +++ b/doc/git-annex.mdwn @@ -1082,6 +1082,11 @@ file contents are present at either of two repositories. The size can be specified with any commonly used units, for example, "0.5 gb" or "100 KiloBytes" +* `--metadata field=value` + + Matches only files that have a metadata field attached with the specified + value. + * `--want-get` Matches files that the preferred content settings for the repository |