2014-02-23 04:08:29 +00:00
|
|
|
{- git-annex metadata
|
|
|
|
-
|
2016-02-27 14:55:02 +00:00
|
|
|
- Copyright 2014-2016 Joey Hess <id@joeyh.name>
|
2014-02-23 04:08:29 +00:00
|
|
|
-
|
|
|
|
- Licensed under the GNU GPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
2014-03-18 22:55:43 +00:00
|
|
|
module Annex.MetaData (
|
|
|
|
genMetaData,
|
2014-07-03 18:35:20 +00:00
|
|
|
dateMetaData,
|
2016-02-27 14:55:02 +00:00
|
|
|
parseModMeta,
|
|
|
|
parseMetaDataMatcher,
|
2014-03-18 22:55:43 +00:00
|
|
|
module X
|
|
|
|
) where
|
2014-02-23 04:08:29 +00:00
|
|
|
|
2016-01-20 20:36:33 +00:00
|
|
|
import Annex.Common
|
2014-02-23 04:08:29 +00:00
|
|
|
import qualified Annex
|
2014-03-18 22:55:43 +00:00
|
|
|
import Types.MetaData as X
|
|
|
|
import Annex.MetaData.StandardFields as X
|
2014-02-23 04:08:29 +00:00
|
|
|
import Logs.MetaData
|
2014-02-24 18:41:33 +00:00
|
|
|
import Annex.CatFile
|
2016-02-27 14:55:02 +00:00
|
|
|
import Utility.Glob
|
2014-02-23 04:08:29 +00:00
|
|
|
|
|
|
|
import qualified Data.Set as S
|
|
|
|
import qualified Data.Map as M
|
|
|
|
import Data.Time.Calendar
|
|
|
|
import Data.Time.Clock
|
|
|
|
import Data.Time.Clock.POSIX
|
|
|
|
|
2014-02-24 18:41:33 +00:00
|
|
|
{- Adds metadata for a file that has just been ingested into the
|
|
|
|
- annex, but has not yet been committed to git.
|
2014-02-23 04:08:29 +00:00
|
|
|
-
|
2014-02-24 18:41:33 +00:00
|
|
|
- When the file has been modified, the metadata is copied over
|
|
|
|
- from the old key to the new key. Note that it looks at the old key as
|
|
|
|
- committed to HEAD -- the new key may or may not have already been staged
|
2016-01-07 18:21:12 +00:00
|
|
|
- in the index.
|
2014-02-24 18:41:33 +00:00
|
|
|
-
|
|
|
|
- Also, can generate new metadata, if configured to do so.
|
2014-02-23 04:08:29 +00:00
|
|
|
-}
|
2014-02-24 18:41:33 +00:00
|
|
|
genMetaData :: Key -> FilePath -> FileStatus -> Annex ()
|
|
|
|
genMetaData key file status = do
|
2017-11-15 20:55:38 +00:00
|
|
|
catKeyFileHEAD file >>= \case
|
2017-09-28 16:56:35 +00:00
|
|
|
Nothing -> noop
|
|
|
|
Just oldkey ->
|
|
|
|
whenM (copyMetaData oldkey key)
|
|
|
|
warncopied
|
2014-02-24 18:41:33 +00:00
|
|
|
whenM (annexGenMetaData <$> Annex.getGitConfig) $ do
|
import metadata from feeds
When annex.genmetadata is set, metadata from the feed is added to files
that are imported from it.
Reused the same feedtitle and itemtitle, feedauthor, itemauthor, etc names
that are used in --template.
Also added title and author, which are the item title/author if available,
falling back to the feed title/author. These are more likely to be common
metadata fields.
(There is a small bit of dupication here, but once git gets
around to packing the object, it will compress it away.)
The itempubdate field is not included in the metadata as a string; instead
it is used to generate year and month fields, same as is done when adding
files with annex.genmetadata set.
This commit was sponsored by Amitai Schlair, who cooincidentially
is responsible for ikiwiki generating nice feed metadata!
2014-07-03 17:46:09 +00:00
|
|
|
curr <- getCurrentMetaData key
|
2014-07-03 18:35:20 +00:00
|
|
|
addMetaData key (dateMetaData mtime curr)
|
import metadata from feeds
When annex.genmetadata is set, metadata from the feed is added to files
that are imported from it.
Reused the same feedtitle and itemtitle, feedauthor, itemauthor, etc names
that are used in --template.
Also added title and author, which are the item title/author if available,
falling back to the feed title/author. These are more likely to be common
metadata fields.
(There is a small bit of dupication here, but once git gets
around to packing the object, it will compress it away.)
The itempubdate field is not included in the metadata as a string; instead
it is used to generate year and month fields, same as is done when adding
files with annex.genmetadata set.
This commit was sponsored by Amitai Schlair, who cooincidentially
is responsible for ikiwiki generating nice feed metadata!
2014-07-03 17:46:09 +00:00
|
|
|
where
|
|
|
|
mtime = posixSecondsToUTCTime $ realToFrac $ modificationTime status
|
2017-09-28 16:56:35 +00:00
|
|
|
warncopied = warning $
|
|
|
|
"Copied metadata from old version of " ++ file ++ " to new version. " ++
|
|
|
|
"If you don't want this copied metadata, run: git annex metadata --remove-all " ++ file
|
2014-02-24 18:41:33 +00:00
|
|
|
|
import metadata from feeds
When annex.genmetadata is set, metadata from the feed is added to files
that are imported from it.
Reused the same feedtitle and itemtitle, feedauthor, itemauthor, etc names
that are used in --template.
Also added title and author, which are the item title/author if available,
falling back to the feed title/author. These are more likely to be common
metadata fields.
(There is a small bit of dupication here, but once git gets
around to packing the object, it will compress it away.)
The itempubdate field is not included in the metadata as a string; instead
it is used to generate year and month fields, same as is done when adding
files with annex.genmetadata set.
This commit was sponsored by Amitai Schlair, who cooincidentially
is responsible for ikiwiki generating nice feed metadata!
2014-07-03 17:46:09 +00:00
|
|
|
{- Generates metadata for a file's date stamp.
|
2014-02-24 18:41:33 +00:00
|
|
|
- Does not overwrite any existing metadata values. -}
|
2014-07-03 18:35:20 +00:00
|
|
|
dateMetaData :: UTCTime -> MetaData -> MetaData
|
|
|
|
dateMetaData mtime old = MetaData $ M.fromList $ filter isnew
|
2014-02-23 04:08:29 +00:00
|
|
|
[ (yearMetaField, S.singleton $ toMetaValue $ show y)
|
|
|
|
, (monthMetaField, S.singleton $ toMetaValue $ show m)
|
2017-10-25 19:11:12 +00:00
|
|
|
, (dayMetaField, S.singleton $ toMetaValue $ show d)
|
2014-02-23 04:08:29 +00:00
|
|
|
]
|
|
|
|
where
|
|
|
|
isnew (f, _) = S.null (currentMetaDataValues f old)
|
2017-10-25 19:11:12 +00:00
|
|
|
(y, m, d) = toGregorian $ utctDay mtime
|
2016-02-27 14:55:02 +00:00
|
|
|
|
|
|
|
{- Parses field=value, field+=value, field-=value, field?=value -}
|
|
|
|
parseModMeta :: String -> Either String ModMeta
|
|
|
|
parseModMeta p = case lastMaybe f of
|
|
|
|
Just '+' -> AddMeta <$> mkMetaField f' <*> v
|
2016-02-29 17:00:46 +00:00
|
|
|
Just '-' -> DelMeta <$> mkMetaField f' <*> (Just <$> v)
|
2016-02-27 14:55:02 +00:00
|
|
|
Just '?' -> MaybeSetMeta <$> mkMetaField f' <*> v
|
2016-07-27 14:46:25 +00:00
|
|
|
_ -> SetMeta <$> mkMetaField f <*> (S.singleton <$> v)
|
2016-02-27 14:55:02 +00:00
|
|
|
where
|
|
|
|
(f, sv) = separate (== '=') p
|
|
|
|
f' = beginning f
|
|
|
|
v = pure (toMetaValue sv)
|
|
|
|
|
|
|
|
{- Parses field=value, field<value, field<=value, field>value, field>=value -}
|
|
|
|
parseMetaDataMatcher :: String -> Either String (MetaField, MetaValue -> Bool)
|
|
|
|
parseMetaDataMatcher p = (,)
|
|
|
|
<$> mkMetaField f
|
|
|
|
<*> pure matcher
|
|
|
|
where
|
|
|
|
(f, op_v) = break (`elem` "=<>") p
|
|
|
|
matcher = case op_v of
|
|
|
|
('=':v) -> checkglob v
|
|
|
|
('<':'=':v) -> checkcmp (<=) v
|
|
|
|
('<':v) -> checkcmp (<) v
|
|
|
|
('>':'=':v) -> checkcmp (>=) v
|
|
|
|
('>':v) -> checkcmp (>) v
|
|
|
|
_ -> checkglob ""
|
|
|
|
checkglob v =
|
|
|
|
let cglob = compileGlob v CaseInsensative
|
|
|
|
in matchGlob cglob . fromMetaValue
|
|
|
|
checkcmp cmp v v' = case (doubleval v, doubleval (fromMetaValue v')) of
|
|
|
|
(Just d, Just d') -> d' `cmp` d
|
|
|
|
_ -> False
|
|
|
|
doubleval v = readish v :: Maybe Double
|