git-annex/Types/FileMatcher.hs

107 lines
3.3 KiB
Haskell
Raw Normal View History

2013-05-25 17:51:27 +00:00
{- git-annex file matcher types
-
- Copyright 2013-2023 Joey Hess <id@joeyh.name>
2013-05-25 17:51:27 +00:00
-
- Licensed under the GNU AGPL version 3 or higher.
2013-05-25 17:51:27 +00:00
-}
module Types.FileMatcher where
import Types.UUID (UUID)
import Types.Key (Key)
import Types.Link (LinkType)
import Types.Mime
import Utility.Matcher (Matcher, Token, MatchDesc)
import Utility.FileSize
import Utility.FileSystemEncoding
import Control.Monad.IO.Class
import qualified Data.Map as M
import qualified Data.Set as S
-- Information about a file and/or a key that can be matched on.
data MatchInfo
= MatchingFile FileInfo
| MatchingInfo ProvidedInfo
| MatchingUserInfo UserProvidedInfo
2013-05-25 17:51:27 +00:00
data FileInfo = FileInfo
2021-03-01 20:34:40 +00:00
{ contentFile :: RawFilePath
-- ^ path to a file containing the content, for operations
-- that examine it
, matchFile :: RawFilePath
2020-12-14 20:52:53 +00:00
-- ^ filepath to match on; may be relative to top of repo or cwd,
-- depending on how globs in preferred content expressions
-- are intended to be matched
, matchKey :: Maybe Key
-- ^ provided if a key is already known
2013-05-25 17:51:27 +00:00
}
data ProvidedInfo = ProvidedInfo
{ providedFilePath :: Maybe RawFilePath
-- ^ filepath to match on, should not be accessed from disk.
, providedKey :: Maybe Key
, providedFileSize :: Maybe FileSize
, providedMimeType :: Maybe MimeType
, providedMimeEncoding :: Maybe MimeEncoding
, providedLinkType :: Maybe LinkType
}
fromkey unlocked files support fromkey: Create an unlocked file when used in an adjusted branch where the file should be unlocked, or when configured by annex.addunlocked. There is some overlap with code in Annex.Ingest, however it's not quite the same because ingesting has a temp file with the content, where here the content, if any, is in the annex object file. So it eg, makes sense for Annex.Ingest to copy the execute mode of the content file, but it does not make sense for fromkey to do that. Also changed in passing to stage the file in git directly, rather than using git add. One consequence of that is that if the file is gitignored, it will still get added, rather than the old behavior: The following paths are ignored by one of your .gitignore files: ignored hint: Use -f if you really want to add them. hint: Turn this message off by running hint: "git config advice.addIgnoredFile false" git-annex: user error (xargs ["-0","git","--git-dir=.git","--work-tree=.","--literal-pathspecs","add","--"] exited 123) That old behavior was a surprise to me, and so I consider it a bug, and doubt anyone would have relied on it. Note that, when on an --hide-missing branch, it is possible to fromkey a key that is not present (needs --force). The annex link or pointer file still gets written in this case. It doesn't seem to make any sense not to write it, because then fromkey would not do anything useful in this case, and this way the file can be committed and synced to master, and the branch re-adjusted to hide the new missing file. This commit was sponsored by Noam Kremen on Patreon.
2021-05-03 15:26:18 +00:00
keyMatchInfoWithoutContent :: Key -> RawFilePath -> MatchInfo
keyMatchInfoWithoutContent key file = MatchingInfo $ ProvidedInfo
{ providedFilePath = Just file
, providedKey = Just key
, providedFileSize = Nothing
, providedMimeType = Nothing
, providedMimeEncoding = Nothing
, providedLinkType = Nothing
}
-- This is used when testing a matcher, with values to match against
-- provided by the user.
data UserProvidedInfo = UserProvidedInfo
{ userProvidedFilePath :: UserInfo FilePath
, userProvidedKey :: UserInfo Key
, userProvidedFileSize :: UserInfo FileSize
, userProvidedMimeType :: UserInfo MimeType
, userProvidedMimeEncoding :: UserInfo MimeEncoding
}
-- This may fail if the user did not provide the information.
type UserInfo a = Either (IO a) a
-- If the UserInfo is not available, accessing it may result in eg an
-- exception being thrown.
getUserInfo :: MonadIO m => UserInfo a -> m a
getUserInfo (Right i) = return i
getUserInfo (Left e) = liftIO e
type FileMatcherMap a = M.Map UUID (FileMatcher a)
type MkLimit a = String -> Either String (MatchFiles a)
type AssumeNotPresent = S.Set UUID
data MatchFiles a = MatchFiles
{ matchAction :: AssumeNotPresent -> MatchInfo -> a Bool
, matchNeedsFileName :: Bool
-- ^ does the matchAction need a filename in order to match?
, matchNeedsFileContent :: Bool
-- ^ does the matchAction need the file content to be present in
-- order to succeed?
, matchNeedsKey :: Bool
-- ^ does the matchAction look at information about the key?
, matchNeedsLocationLog :: Bool
-- ^ does the matchAction look at the location log?
, matchDesc :: Bool -> MatchDesc
-- ^ displayed to the user to describe whether it matched or not
}
type FileMatcher a = Matcher (MatchFiles a)
-- This is a matcher that can have tokens added to it while it's being
2023-03-14 02:39:16 +00:00
-- built, and once complete is compiled to an unchangeable matcher.
data ExpandableMatcher a
= BuildingMatcher [Token (MatchFiles a)]
| CompleteMatcher (Matcher (MatchFiles a))