summaryrefslogtreecommitdiff
path: root/Git/CheckAttr.hs
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2013-10-15 16:04:26 -0400
committerGravatar Joey Hess <joey@kitenet.net>2013-10-15 16:05:27 -0400
commitb772d27ce905b361127334e12e55bda0f3ee21b7 (patch)
treec416201e4d0147a8c324fdd0b9938312b2831903 /Git/CheckAttr.hs
parentb9f0688ed7f933185e38ffc487e07888972d4842 (diff)
Deal with git check-attr -z output format change in git 1.8.5.
I have not actually tested with 1.8.5, which is not yet relesaed, but git.git commit f7cd8c50b9ab83e084e8f52653ecc8d90665eef2 changes -z to also apply to output, without regards to back-compat. (But with pretty good reasons.) New code should work with both versions, by fingerprinting for NULs and newlines.
Diffstat (limited to 'Git/CheckAttr.hs')
-rw-r--r--Git/CheckAttr.hs39
1 files changed, 34 insertions, 5 deletions
diff --git a/Git/CheckAttr.hs b/Git/CheckAttr.hs
index 24fa2be87..40259881a 100644
--- a/Git/CheckAttr.hs
+++ b/Git/CheckAttr.hs
@@ -13,6 +13,8 @@ import Git.Command
import qualified Git.BuildVersion
import qualified Utility.CoProcess as CoProcess
+import System.IO.Error
+
type CheckAttrHandle = (CoProcess.CoProcessHandle, [Attr], String)
type Attr = String
@@ -37,16 +39,41 @@ checkAttrStop (h, _, _) = CoProcess.stop h
{- Gets an attribute of a file. -}
checkAttr :: CheckAttrHandle -> Attr -> FilePath -> IO String
checkAttr (h, attrs, cwd) want file = do
- pairs <- CoProcess.query h send receive
+ pairs <- CoProcess.query h send (receive "")
let vals = map snd $ filter (\(attr, _) -> attr == want) pairs
case vals of
[v] -> return v
_ -> error $ "unable to determine " ++ want ++ " attribute of " ++ file
where
send to = hPutStr to $ file' ++ "\0"
- receive from = forM attrs $ \attr -> do
- l <- hGetLine from
- return (attr, attrvalue attr l)
+ receive c from = do
+ s <- hGetSomeString from 1024
+ if null s
+ then eofError
+ else do
+ let v = c ++ s
+ maybe (receive v from) return (parse v)
+ eofError = ioError $ mkIOError userErrorType "git check-attr EOF" Nothing Nothing
+ parse s
+ -- new null separated output
+ | '\0' `elem` s = if "\0" `isSuffixOf` s
+ then
+ let bits = segment (== '\0') s
+ in if length bits == numattrs * 3
+ then Just $ getattrvalues bits []
+ else Nothing -- more attributes to come
+ else Nothing -- output incomplete
+ -- old one line per value output
+ | otherwise = if "\n" `isSuffixOf` s
+ then
+ let ls = lines s
+ in if length ls == numattrs
+ then Just $ map (\(attr, val) -> (attr, oldattrvalue attr val))
+ (zip attrs ls)
+ else Nothing -- more attributes to come
+ else Nothing -- line incomplete
+ numattrs = length attrs
+
{- Before git 1.7.7, git check-attr worked best with
- absolute filenames; using them worked around some bugs
- with relative filenames.
@@ -58,7 +85,9 @@ checkAttr (h, attrs, cwd) want file = do
file'
| oldgit = absPathFrom cwd file
| otherwise = relPathDirToFile cwd $ absPathFrom cwd file
- attrvalue attr l = end bits !! 0
+ oldattrvalue attr l = end bits !! 0
where
bits = split sep l
sep = ": " ++ attr ++ ": "
+ getattrvalues (_filename:attr:val:rest) c = getattrvalues rest ((attr,val):c)
+ getattrvalues _ c = c