rename Git.Filename to Git.Quote
authorJoey Hess <joeyh@joeyh.name>
Wed, 12 Apr 2023 21:18:29 +0000 (17:18 -0400)
committerJoey Hess <joeyh@joeyh.name>
Wed, 12 Apr 2023 21:22:03 +0000 (17:22 -0400)
16 files changed:
Annex/Common.hs
Annex/Export.hs
Annex/LockPool/PosixOrPid.hs
Git/DiffTree.hs
Git/FilePath.hs
Git/Filename.hs [deleted file]
Git/LsTree.hs
Git/Quote.hs [new file with mode: 0644]
Logs/Transfer.hs
Messages.hs
Messages/Internal.hs
Messages/Serialized.hs
Test.hs
Types/ActionItem.hs
Types/GitConfig.hs
git-annex.cabal

index fc0a25b1d04e5ae42a8382cf6decf80014c85411..13174c0b3708920be0ce6011a009c94b613b48f6 100644 (file)
@@ -10,7 +10,7 @@ import Annex as X (gitRepo, inRepo, fromRepo, calcRepo, calcRepo')
 import Annex.Locations as X
 import Annex.Debug as X (fastDebug, debug)
 import Messages as X
-import Git.Filename as X
+import Git.Quote as X
 #ifndef mingw32_HOST_OS
 import System.Posix.IO as X hiding (createPipe)
 #endif
index 489d8984e05fd9dafecaf6de9b306035099a7e1f..60039ef3b9bfabfc73ce475a26fddda1446d143d 100644 (file)
@@ -15,7 +15,7 @@ import Types
 import Types.Key
 import qualified Git
 import qualified Types.Remote as Remote
-import Git.Filename
+import Git.Quote
 import Messages
 
 import Data.Maybe
index c7d7596ed874c7e7cfafa05c0d24c8d7e8528052..04139687f84506906cd8393201fd512aad106f54 100644 (file)
@@ -32,7 +32,7 @@ import Utility.LockPool.STM (LockFile, LockMode(..))
 import Utility.LockFile.LockStatus
 import Config (pidLockFile)
 import Messages (warning)
-import Git.Filename
+import Git.Quote
 
 import System.Posix
 
index 3be5cb980a31326e0cbe282571cae7a5b898bd2a..102658922b8d66bf3f1f73907b0d733dba95a566 100644 (file)
@@ -29,7 +29,7 @@ import Git.Sha
 import Git.Command
 import Git.FilePath
 import Git.DiffTreeItem
-import qualified Git.Filename
+import qualified Git.Quote
 import qualified Git.Ref
 import Utility.Attoparsec
 
@@ -133,6 +133,6 @@ parserDiffRaw f = DiffTreeItem
        <*> (maybe (fail "bad dstsha") return . extractSha =<< nextword)
        <* A8.char ' '
        <*> A.takeByteString
-       <*> pure (asTopFilePath $ fromInternalGitPath $ Git.Filename.unquote f)
+       <*> pure (asTopFilePath $ fromInternalGitPath $ Git.Quote.unquote f)
   where
        nextword = A8.takeTill (== ' ')
index 37b046fc3ff51798c356c35b6cd3f0d01e835fac..fde748593008e38f66333a03dc11a98af4abc956 100644 (file)
@@ -30,7 +30,7 @@ module Git.FilePath (
 
 import Common
 import Git
-import Git.Filename
+import Git.Quote
 
 import qualified System.FilePath.ByteString as P
 import qualified System.FilePath.Posix.ByteString
diff --git a/Git/Filename.hs b/Git/Filename.hs
deleted file mode 100644 (file)
index 2baea62..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-{- Some git commands output quoted filenames, in a rather annoyingly complex
- - C-style encoding.
- -
- - Copyright 2010-2023 Joey Hess <id@joeyh.name>
- -
- - Licensed under the GNU AGPL version 3 or higher.
- -}
-
-{-# LANGUAGE OverloadedStrings, TypeSynonymInstances #-}
-
-module Git.Filename (
-       unquote,
-       quote,
-       noquote,
-       QuotePath(..),
-       StringContainingQuotedPath(..),
-       quotedPaths,
-       prop_quote_unquote_roundtrip,
-) where
-
-import Common
-import Utility.Format (decode_c, encode_c, encode_c', isUtf8Byte)
-import Utility.QuickCheck
-import Utility.SafeOutput
-
-import Data.Char
-import Data.Word
-import Data.String
-import qualified Data.ByteString as S
-import qualified Data.Semigroup as Sem
-import Prelude
-
-unquote :: S.ByteString -> RawFilePath
-unquote b = case S.uncons b of
-       Nothing -> b
-       Just (h, t)
-               | h /= q -> b
-               | otherwise -> case S.unsnoc t of
-                       Nothing -> b
-                       Just (i, l)
-                               | l /= q -> b
-                               | otherwise -> decode_c i
-  where
-       q :: Word8
-       q = fromIntegral (ord '"')
-
--- always encodes and double quotes, even in cases that git does not
-quoteAlways :: RawFilePath -> S.ByteString
-quoteAlways s = "\"" <> encode_c needencode s <> "\""
-  where
-       needencode c = isUtf8Byte c || c == fromIntegral (ord '"')
-
--- git config core.quotePath controls whether to quote unicode characters
-newtype QuotePath = QuotePath Bool
-
-class Quoteable t where
-       -- double quotes and encodes when git would
-       quote :: QuotePath -> t -> S.ByteString
-
-       noquote :: t -> S.ByteString
-
-instance Quoteable RawFilePath where
-       quote (QuotePath qp) s = case encode_c' needencode s of
-               Nothing -> s
-               Just s' -> "\"" <> s' <> "\""
-         where
-               needencode c
-                       | c == fromIntegral (ord '"') = True
-                       | qp = isUtf8Byte c
-                       | otherwise = False
-
-       noquote = id
-
--- Allows building up a string that contains paths, which will get quoted.
--- With OverloadedStrings, strings are passed through without quoting.
--- Eg: QuotedPath f <> ": not found"
-data StringContainingQuotedPath
-       = UnquotedString String 
-       | UnquotedByteString S.ByteString 
-       | QuotedPath RawFilePath
-       | StringContainingQuotedPath :+: StringContainingQuotedPath
-       deriving (Show, Eq)
-
-quotedPaths :: [RawFilePath] -> StringContainingQuotedPath
-quotedPaths [] = mempty
-quotedPaths (p:ps) = QuotedPath p <> if null ps
-       then mempty
-       else " " <> quotedPaths ps
-
-instance Quoteable StringContainingQuotedPath where
-       quote _ (UnquotedString s) = safeOutput (encodeBS s)
-       quote _ (UnquotedByteString s) = safeOutput s
-       quote qp (QuotedPath p) = quote qp p
-       quote qp (a :+: b) = quote qp a <> quote qp b
-
-       noquote (UnquotedString s) = encodeBS s
-       noquote (UnquotedByteString s) = s
-       noquote (QuotedPath p) = p
-       noquote (a :+: b) = noquote a <> noquote b
-
-instance IsString StringContainingQuotedPath where
-       fromString = UnquotedByteString . encodeBS
-
-instance Sem.Semigroup StringContainingQuotedPath where
-       UnquotedString a <> UnquotedString b = UnquotedString (a <> b)
-       UnquotedByteString a <> UnquotedByteString b = UnquotedByteString (a <> b)
-       a <> b = a :+: b
-
-instance Monoid StringContainingQuotedPath where
-       mempty = UnquotedByteString mempty
-
--- Encoding and then decoding roundtrips only when the string does not
--- contain high unicode, because eg, both "\12345" and "\227\128\185"
--- are encoded to "\343\200\271".
---
--- That is not a real-world problem, and using TestableFilePath
--- limits what's tested to ascii, so avoids running into it.
-prop_quote_unquote_roundtrip :: TestableFilePath -> Bool
-prop_quote_unquote_roundtrip ts = 
-       s == fromRawFilePath (unquote (quoteAlways (toRawFilePath s)))
-  where
-       s = fromTestableFilePath ts
index addd5b1069770b099262f3457af507d57f4ae83e..9129d18fc49a2156d2f8a2765de3f3f5b76a4f63 100644 (file)
@@ -23,7 +23,7 @@ import Common
 import Git
 import Git.Command
 import Git.FilePath
-import qualified Git.Filename
+import qualified Git.Quote
 import Utility.Attoparsec
 
 import Numeric
@@ -137,7 +137,7 @@ parserLsTree long = case long of
                -- sha
                <*> (Ref <$> A8.takeTill A8.isSpace)
 
-       fileparser = asTopFilePath . Git.Filename.unquote <$> A.takeByteString
+       fileparser = asTopFilePath . Git.Quote.unquote <$> A.takeByteString
 
        sizeparser = fmap Just A8.decimal
 
diff --git a/Git/Quote.hs b/Git/Quote.hs
new file mode 100644 (file)
index 0000000..2ca442e
--- /dev/null
@@ -0,0 +1,122 @@
+{- Some git commands output quoted filenames, in a rather annoyingly complex
+ - C-style encoding.
+ -
+ - Copyright 2010-2023 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+{-# LANGUAGE OverloadedStrings, TypeSynonymInstances #-}
+
+module Git.Quote (
+       unquote,
+       quote,
+       noquote,
+       QuotePath(..),
+       StringContainingQuotedPath(..),
+       quotedPaths,
+       prop_quote_unquote_roundtrip,
+) where
+
+import Common
+import Utility.Format (decode_c, encode_c, encode_c', isUtf8Byte)
+import Utility.QuickCheck
+import Utility.SafeOutput
+
+import Data.Char
+import Data.Word
+import Data.String
+import qualified Data.ByteString as S
+import qualified Data.Semigroup as Sem
+import Prelude
+
+unquote :: S.ByteString -> RawFilePath
+unquote b = case S.uncons b of
+       Nothing -> b
+       Just (h, t)
+               | h /= q -> b
+               | otherwise -> case S.unsnoc t of
+                       Nothing -> b
+                       Just (i, l)
+                               | l /= q -> b
+                               | otherwise -> decode_c i
+  where
+       q :: Word8
+       q = fromIntegral (ord '"')
+
+-- always encodes and double quotes, even in cases that git does not
+quoteAlways :: RawFilePath -> S.ByteString
+quoteAlways s = "\"" <> encode_c needencode s <> "\""
+  where
+       needencode c = isUtf8Byte c || c == fromIntegral (ord '"')
+
+-- git config core.quotePath controls whether to quote unicode characters
+newtype QuotePath = QuotePath Bool
+
+class Quoteable t where
+       -- double quotes and encodes when git would
+       quote :: QuotePath -> t -> S.ByteString
+
+       noquote :: t -> S.ByteString
+
+instance Quoteable RawFilePath where
+       quote (QuotePath qp) s = case encode_c' needencode s of
+               Nothing -> s
+               Just s' -> "\"" <> s' <> "\""
+         where
+               needencode c
+                       | c == fromIntegral (ord '"') = True
+                       | qp = isUtf8Byte c
+                       | otherwise = False
+
+       noquote = id
+
+-- Allows building up a string that contains paths, which will get quoted.
+-- With OverloadedStrings, strings are passed through without quoting.
+-- Eg: QuotedPath f <> ": not found"
+data StringContainingQuotedPath
+       = UnquotedString String 
+       | UnquotedByteString S.ByteString 
+       | QuotedPath RawFilePath
+       | StringContainingQuotedPath :+: StringContainingQuotedPath
+       deriving (Show, Eq)
+
+quotedPaths :: [RawFilePath] -> StringContainingQuotedPath
+quotedPaths [] = mempty
+quotedPaths (p:ps) = QuotedPath p <> if null ps
+       then mempty
+       else " " <> quotedPaths ps
+
+instance Quoteable StringContainingQuotedPath where
+       quote _ (UnquotedString s) = safeOutput (encodeBS s)
+       quote _ (UnquotedByteString s) = safeOutput s
+       quote qp (QuotedPath p) = quote qp p
+       quote qp (a :+: b) = quote qp a <> quote qp b
+
+       noquote (UnquotedString s) = encodeBS s
+       noquote (UnquotedByteString s) = s
+       noquote (QuotedPath p) = p
+       noquote (a :+: b) = noquote a <> noquote b
+
+instance IsString StringContainingQuotedPath where
+       fromString = UnquotedByteString . encodeBS
+
+instance Sem.Semigroup StringContainingQuotedPath where
+       UnquotedString a <> UnquotedString b = UnquotedString (a <> b)
+       UnquotedByteString a <> UnquotedByteString b = UnquotedByteString (a <> b)
+       a <> b = a :+: b
+
+instance Monoid StringContainingQuotedPath where
+       mempty = UnquotedByteString mempty
+
+-- Encoding and then decoding roundtrips only when the string does not
+-- contain high unicode, because eg, both "\12345" and "\227\128\185"
+-- are encoded to "\343\200\271".
+--
+-- That is not a real-world problem, and using TestableFilePath
+-- limits what's tested to ascii, so avoids running into it.
+prop_quote_unquote_roundtrip :: TestableFilePath -> Bool
+prop_quote_unquote_roundtrip ts = 
+       s == fromRawFilePath (unquote (quoteAlways (toRawFilePath s)))
+  where
+       s = fromTestableFilePath ts
index a35474781d7ef7725119677da24e3c10fbc05d6b..41b62a8847797338b831eaaad0749e2d735f464e 100644 (file)
@@ -14,7 +14,7 @@ import Types.Transfer
 import Types.ActionItem
 import Annex.Common
 import qualified Git
-import qualified Git.Filename
+import qualified Git.Quote
 import Utility.Metered
 import Utility.Percentage
 import Utility.PID
@@ -32,7 +32,7 @@ import Control.Concurrent.STM
 import qualified Data.ByteString.Char8 as B8
 import qualified System.FilePath.ByteString as P
 
-describeTransfer :: Git.Filename.QuotePath -> Transfer -> TransferInfo -> String
+describeTransfer :: Git.Quote.QuotePath -> Transfer -> TransferInfo -> String
 describeTransfer qp t info = unwords
        [ show $ transferDirection t
        , show $ transferUUID t
index c8395ff4c79d9f04bff77284abafffed66ca5ddd..565822365c71eb787233ef8adbde28a545dbbdf5 100644 (file)
@@ -69,7 +69,7 @@ import Messages.Concurrent
 import Annex.Debug
 import Annex.Concurrent.Utility
 import Utility.SafeOutput
-import Git.Filename
+import Git.Quote
 import qualified Messages.JSON as JSON
 import qualified Annex
 
index 0b975cf74cc073a6b300cd8b9ad9fdbefd7f1d49..a16c7d2c61abdc314a677c06cb15a53579086ef0 100644 (file)
@@ -13,7 +13,7 @@ import Types.Messages
 import Messages.Concurrent
 import qualified Messages.JSON as JSON
 import Messages.JSON (JSONBuilder)
-import Git.Filename
+import Git.Quote
 import Types.GitConfig
 
 import qualified Data.ByteString as S
index 2e8ed00d5ff0344296b5b1ef62d3988812df7f8c..494df5aac52bdc10b8ff4fce8a43399cd66b1820 100644 (file)
@@ -21,7 +21,7 @@ import Messages.Internal
 import Messages.Progress
 import qualified Messages.JSON as JSON
 import Utility.Metered (BytesProcessed, setMeterTotalSize)
-import Git.Filename
+import Git.Quote
 
 import Control.Monad.IO.Class (MonadIO)
 
diff --git a/Test.hs b/Test.hs
index 237eba82b9e407553178c0ea4fe2cce5bb762bdc..a9c7336a70ab6ac2fceecee8375d8d2324238ee0 100644 (file)
--- a/Test.hs
+++ b/Test.hs
@@ -30,7 +30,7 @@ import qualified Utility.RawFilePath as R
 
 import qualified Utility.ShellEscape
 import qualified Annex
-import qualified Git.Filename
+import qualified Git.Quote
 import qualified Git.Types
 import qualified Git.Ref
 import qualified Git.LsTree
@@ -151,7 +151,7 @@ tests n crippledfilesystem adjustedbranchok opts =
 
 properties :: TestTree
 properties = localOption (QuickCheckTests 1000) $ testGroup "QuickCheck" $
-       [ testProperty "prop_quote_unquote_roundtrip" Git.Filename.prop_quote_unquote_roundtrip
+       [ testProperty "prop_quote_unquote_roundtrip" Git.Quote.prop_quote_unquote_roundtrip
        , testProperty "prop_encode_c_decode_c_roundtrip" Utility.Format.prop_encode_c_decode_c_roundtrip
        , testProperty "prop_isomorphic_key_encode" Key.prop_isomorphic_key_encode
        , testProperty "prop_isomorphic_shellEscape" Utility.ShellEscape.prop_isomorphic_shellEscape
index deca2ad1374d0f5d974d3b475608febb0a1c1848..373d7861438e180777056c0a9e27f0696b80fdee 100644 (file)
@@ -15,7 +15,7 @@ module Types.ActionItem (
 import Key
 import Types.Transfer
 import Git.FilePath
-import Git.Filename (StringContainingQuotedPath(..))
+import Git.Quote (StringContainingQuotedPath(..))
 import Utility.FileSystemEncoding
 
 data ActionItem 
index e71e22d4a3f07729d02c8d7d29b63b702df7399a..ea7388368b0db19a023e05966879972af0c4b8ff 100644 (file)
@@ -32,7 +32,7 @@ import Git.Types
 import Git.ConfigTypes
 import Git.Remote (isRemoteKey, remoteKeyToRemoteName)
 import Git.Branch (CommitMode(..))
-import Git.Filename (QuotePath(..))
+import Git.Quote (QuotePath(..))
 import Utility.DataUnits
 import Config.Cost
 import Types.UUID
index c11047d2da6137972f0edced6fd6bc724374693c..af7eecfadfbaa56d692ab1fba525bc8bded32bd0 100644 (file)
@@ -856,7 +856,6 @@ Executable git-annex
     Git.Env
     Git.FileMode
     Git.FilePath
-    Git.Filename
     Git.FilterProcess
     Git.Fsck
     Git.GCrypt
@@ -871,6 +870,7 @@ Executable git-annex
     Git.Objects
     Git.PktLine
     Git.Queue
+    Git.Quote
     Git.Ref
     Git.RefLog
     Git.Remote