filepath 1.4.102.0 → 1.4.200.0
raw patch · 13 files changed
+50/−92 lines, 13 filesdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: base
API changes (from Hackage documentation)
- System.OsPath.Encoding.Internal: isAsyncException :: Exception e => e -> Bool
- System.OsPath.Encoding.Internal: trySafe :: Exception e => IO a -> IO (Either e a)
Files
- System/FilePath/Internal.hs +12/−38
- System/OsPath/Data/ByteString/Short.hs +3/−1
- System/OsPath/Data/ByteString/Short/Internal.hs +7/−3
- System/OsPath/Data/ByteString/Short/Word16.hs +1/−1
- System/OsPath/Encoding/Internal.hs +5/−27
- System/OsString.hs +1/−1
- System/OsString/Common.hs +6/−7
- System/OsString/Internal.hs +1/−1
- System/OsString/Internal/Types.hs +1/−1
- changelog.md +2/−6
- filepath.cabal +2/−2
- tests/filepath-equivalent-tests/TestEquiv.hs +9/−2
- tests/filepath-tests/TestGen.hs +0/−2
System/FilePath/Internal.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE PatternGuards #-} {-# LANGUAGE TypeApplications #-}-{-# LANGUAGE MultiWayIf #-} -- This template expects CPP definitions for: -- MODULE_NAME = Posix | Windows@@ -130,10 +129,9 @@ #define FILEPATH FilePath #else import Prelude (fromIntegral)-import Control.Exception ( SomeException, evaluate, displayException )+import Control.Exception ( SomeException, evaluate, try, displayException ) import Control.DeepSeq (force) import GHC.IO (unsafePerformIO)-import System.OsPath.Encoding.Internal (trySafe) import qualified Data.Char as C #ifdef WINDOWS import GHC.IO.Encoding.Failure ( CodingFailureMode(..) )@@ -604,7 +602,6 @@ -- > Posix: splitFileName "/" == ("/","") -- > Windows: splitFileName "c:" == ("c:","") -- > Windows: splitFileName "\\\\?\\A:\\fred" == ("\\\\?\\A:\\","fred")--- > Windows: splitFileName "\\\\?\\A:" == ("\\\\?\\A:","") splitFileName :: FILEPATH -> (STRING, STRING) splitFileName x = if null path then (dotSlash, file)@@ -647,43 +644,20 @@ -- or UNC location "\\?\UNC\foo", where path separator is a part of the drive name. -- We can test this by trying dropDrive and falling back to splitDrive. | isWindows- = case uncons2 dirSlash of- Just (s1, s2, bs')- | isPathSeparator s1- -- If bs' is empty, then s2 as the last character of dirSlash must be a path separator,- -- so we are in the middle of shared drive.- -- Otherwise, since s1 is a path separator, we might be in the middle of UNC path.- , null bs' || maybe False isIncompleteUNC (readDriveUNC dirSlash)- -> (fp, mempty)- -- This handles inputs like "//?/A:" and "//?/A:foo"- | isPathSeparator s1- , isPathSeparator s2- , Just (s3, s4, bs'') <- uncons2 bs'- , s3 == _question- , isPathSeparator s4- , null bs''- , Just (drive, rest) <- readDriveLetter file- -> (dirSlash <> drive, rest)- _ -> (dirSlash, file)+ , Just (s1, _s2, bs') <- uncons2 dirSlash+ , isPathSeparator s1+ -- If bs' is empty, then s2 as the last character of dirSlash must be a path separator,+ -- so we are in the middle of shared drive.+ -- Otherwise, since s1 is a path separator, we might be in the middle of UNC path.+ , null bs' || maybe False isIncompleteUNC (readDriveUNC dirSlash)+ = (fp, mempty) | otherwise- = (dirSlash, file)+ = (dirSlash, file) where (dirSlash, file) = breakEnd isPathSeparator fp- dropExcessTrailingPathSeparators x- | hasTrailingPathSeparator x- , let x' = dropWhileEnd isPathSeparator x- , otherwise = if | null x' -> singleton (last x)- | otherwise -> addTrailingPathSeparator x'- | otherwise = x - -- an "incomplete" UNC is one without a path (but potentially a drive) isIncompleteUNC (pref, suff) = null suff && not (hasPenultimateColon pref)-- -- e.g. @//?/a:/@ or @//?/a://@, but not @//?/a:@- hasPenultimateColon pref- | hasTrailingPathSeparator pref- = maybe False (maybe False ((== _colon) . snd) . unsnoc . fst) . unsnoc . dropExcessTrailingPathSeparators $ pref- | otherwise = False+ hasPenultimateColon = maybe False (maybe False ((== _colon) . snd) . unsnoc . fst) . unsnoc -- | Set the filename. --@@ -1274,12 +1248,12 @@ #ifdef WINDOWS fromString :: P.String -> STRING fromString str = P.either (P.error . P.show) P.id $ unsafePerformIO $ do- r <- trySafe @SomeException $ GHC.withCStringLen (mkUTF16le ErrorOnCodingFailure) str $ \cstr -> packCStringLen cstr+ r <- try @SomeException $ GHC.withCStringLen (mkUTF16le ErrorOnCodingFailure) str $ \cstr -> packCStringLen cstr evaluate $ force $ first displayException r #else fromString :: P.String -> STRING fromString str = P.either (P.error . P.show) P.id $ unsafePerformIO $ do- r <- trySafe @SomeException $ GHC.withCStringLen (mkUTF8 ErrorOnCodingFailure) str $ \cstr -> packCStringLen cstr+ r <- try @SomeException $ GHC.withCStringLen (mkUTF8 ErrorOnCodingFailure) str $ \cstr -> packCStringLen cstr evaluate $ force $ first displayException r #endif
System/OsPath/Data/ByteString/Short.hs view
@@ -23,7 +23,9 @@ -- -- > import qualified Data.ByteString.Short as B.Short ---module System.OsPath.Data.ByteString.Short (+module System.OsPath.Data.ByteString.Short {-# DEPRECATED "Use System.OsString.Data.ByteString.Short from os-string >= 2.0.0 package instead. This module will be removed in filepath >= 1.5." #-}++ ( -- * The @ShortByteString@ type
System/OsPath/Data/ByteString/Short/Internal.hs view
@@ -17,7 +17,7 @@ -- -- Internal low-level utilities mostly for 'System.OsPath.Data.ByteString.Short.Word16', -- such as byte-array operations and other stuff not meant to be exported from Word16 module.-module System.OsPath.Data.ByteString.Short.Internal where+module System.OsPath.Data.ByteString.Short.Internal {-# DEPRECATED "Use System.OsString.Data.ByteString.Short.Internal from os-string >= 2.0.0 package instead. This module will be removed in filepath >= 1.5." #-} where import Control.Monad.ST import Control.Exception (assert, throwIO)@@ -164,9 +164,13 @@ action buf where l = length bs --- | /O(n) construction./ Use a @ShortByteString@ with a function requiring a @CStringLen@.--- As for @useAsCString@ this function makes a copy of the original @ShortByteString@.+-- | /O(n) construction./ Use a @ShortByteString@ with a function requiring a 'CStringLen'.+-- As for 'useAsCString' this function makes a copy of the original @ShortByteString@. -- It must not be stored or used after the subcomputation finishes.+--+-- Beware that this function does not add a terminating @\NUL@ byte at the end of 'CStringLen'.+-- If you need to construct a pointer to a null-terminated sequence, use 'useAsCString'+-- (and measure length independently if desired). -- -- @since 0.10.10.0 useAsCStringLen :: ShortByteString -> (CStringLen -> IO a) -> IO a
System/OsPath/Data/ByteString/Short/Word16.hs view
@@ -29,7 +29,7 @@ -- -- All functions will error out if the input string is not a valid UTF16 stream (uneven number of bytes). -- So use this module with caution.-module System.OsPath.Data.ByteString.Short.Word16 (+module System.OsPath.Data.ByteString.Short.Word16 {-# DEPRECATED "Use System.OsString.Data.ByteString.Short.Word16 from os-string >= 2.0.0 package instead. This module will be removed in filepath >= 1.5." #-} ( -- * The @ShortByteString@ type and representation ShortByteString(..),
System/OsPath/Encoding/Internal.hs view
@@ -6,7 +6,7 @@ {-# OPTIONS_GHC -funbox-strict-fields #-} -module System.OsPath.Encoding.Internal where+module System.OsPath.Encoding.Internal {-# DEPRECATED "Use System.OsString.Encoding.Internal from os-string >= 2.0.0 package instead. This module will be removed in filepath >= 1.5." #-} where import qualified System.OsPath.Data.ByteString.Short as BS8 import qualified System.OsPath.Data.ByteString.Short.Word16 as BS16@@ -19,7 +19,7 @@ import GHC.IO.Encoding.Failure import GHC.IO.Encoding.Types import Data.Bits-import Control.Exception (SomeException, SomeAsyncException(..), Exception (displayException), evaluate, catch, throwIO, toException, fromException)+import Control.Exception (SomeException, try, Exception (displayException), evaluate) import qualified GHC.Foreign as GHC import Data.Either (Either) import GHC.IO (unsafePerformIO)@@ -31,7 +31,7 @@ import Foreign.C (CStringLen) import Data.Char (chr) import Foreign-import Prelude (FilePath, Either(..))+import Prelude (FilePath) import GHC.IO.Encoding (getFileSystemEncoding) -- -----------------------------------------------------------------------------@@ -277,13 +277,13 @@ -- | Decode with the given 'TextEncoding'. decodeWithTE :: TextEncoding -> BS8.ShortByteString -> Either EncodingException String decodeWithTE enc ba = unsafePerformIO $ do- r <- trySafe @SomeException $ BS8.useAsCStringLen ba $ \fp -> GHC.peekCStringLen enc fp+ r <- try @SomeException $ BS8.useAsCStringLen ba $ \fp -> GHC.peekCStringLen enc fp evaluate $ force $ first (flip EncodingError Nothing . displayException) r -- | Encode with the given 'TextEncoding'. encodeWithTE :: TextEncoding -> String -> Either EncodingException BS8.ShortByteString encodeWithTE enc str = unsafePerformIO $ do- r <- trySafe @SomeException $ GHC.withCStringLen enc str $ \cstr -> BS8.packCStringLen cstr+ r <- try @SomeException $ GHC.withCStringLen enc str $ \cstr -> BS8.packCStringLen cstr evaluate $ force $ first (flip EncodingError Nothing . displayException) r -- -----------------------------------------------------------------------------@@ -347,25 +347,3 @@ wNUL :: Word16 wNUL = 0x00---- -------------------------------------------------------------------------------- Exceptions------- | Like 'try', but rethrows async exceptions.-trySafe :: Exception e => IO a -> IO (Either e a)-trySafe ioA = catch action eHandler- where- action = do- v <- ioA- return (Right v)- eHandler e- | isAsyncException e = throwIO e- | otherwise = return (Left e)--isAsyncException :: Exception e => e -> Bool-isAsyncException e =- case fromException (toException e) of- Just (SomeAsyncException _) -> True- Nothing -> False-
System/OsString.hs view
@@ -14,7 +14,7 @@ -- -- It captures the notion of syscall specific encoding (or the lack thereof) to avoid roundtrip issues -- and memory fragmentation by using unpinned byte arrays. Bytes are not touched or interpreted.-module System.OsString+module System.OsString {-# DEPRECATED "Use System.OsString from os-string >= 2.0.0 package instead. This module will be removed in filepath >= 1.5." #-} ( -- * String types OsString
System/OsString/Common.hs view
@@ -11,7 +11,7 @@ #define POSIX_DOC #endif -module System.OsString.MODULE_NAME+module System.OsString.MODULE_NAME {-# DEPRECATED "Use System.OsString.MODULE_NAME from os-string >= 2.0.0 package instead. This module will be removed in filepath >= 1.5." #-} ( -- * Types #ifdef WINDOWS@@ -60,7 +60,7 @@ import Data.ByteString.Internal ( ByteString ) import Control.Exception- ( SomeException, displayException )+ ( SomeException, try, displayException ) import Control.DeepSeq ( force ) import Data.Bifunctor ( first ) import GHC.IO@@ -73,7 +73,6 @@ import GHC.IO.Encoding.Failure ( CodingFailureMode(..) )-import System.OsPath.Encoding.Internal (trySafe) #ifdef WINDOWS import System.OsPath.Encoding import System.IO@@ -117,10 +116,10 @@ -> Either EncodingException PLATFORM_STRING encodeWith enc str = unsafePerformIO $ do #ifdef WINDOWS- r <- trySafe @SomeException $ GHC.withCStringLen enc str $ \cstr -> WindowsString <$> BS8.packCStringLen cstr+ r <- try @SomeException $ GHC.withCStringLen enc str $ \cstr -> WindowsString <$> BS8.packCStringLen cstr evaluate $ force $ first (flip EncodingError Nothing . displayException) r #else- r <- trySafe @SomeException $ GHC.withCStringLen enc str $ \cstr -> PosixString <$> BS.packCStringLen cstr+ r <- try @SomeException $ GHC.withCStringLen enc str $ \cstr -> PosixString <$> BS.packCStringLen cstr evaluate $ force $ first (flip EncodingError Nothing . displayException) r #endif @@ -177,7 +176,7 @@ -> PLATFORM_STRING -> Either EncodingException String decodeWith winEnc (WindowsString ba) = unsafePerformIO $ do- r <- trySafe @SomeException $ BS8.useAsCStringLen ba $ \fp -> GHC.peekCStringLen winEnc fp+ r <- try @SomeException $ BS8.useAsCStringLen ba $ \fp -> GHC.peekCStringLen winEnc fp evaluate $ force $ first (flip EncodingError Nothing . displayException) r #else -- | Decode a 'PosixString' with the specified encoding.@@ -187,7 +186,7 @@ -> PLATFORM_STRING -> Either EncodingException String decodeWith unixEnc (PosixString ba) = unsafePerformIO $ do- r <- trySafe @SomeException $ BS.useAsCStringLen ba $ \fp -> GHC.peekCStringLen unixEnc fp+ r <- try @SomeException $ BS.useAsCStringLen ba $ \fp -> GHC.peekCStringLen unixEnc fp evaluate $ force $ first (flip EncodingError Nothing . displayException) r #endif
System/OsString/Internal.hs view
@@ -2,7 +2,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE UnliftedFFITypes #-} -module System.OsString.Internal where+module System.OsString.Internal {-# DEPRECATED "Use System.OsString.Internal from os-string >= 2.0.0 package instead. This module will be removed in filepath >= 1.5." #-} where import System.OsString.Internal.Types
System/OsString/Internal/Types.hs view
@@ -8,7 +8,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE PatternSynonyms #-} -module System.OsString.Internal.Types+module System.OsString.Internal.Types {-# DEPRECATED "Use System.OsString.Internal.Types from os-string >= 2.0.0 package instead. This module will be removed in filepath >= 1.5." #-} ( WindowsString(..) , pattern WS
changelog.md view
@@ -2,13 +2,9 @@ _Note: below all `FilePath` values are unquoted, so `\\` really means two backslashes._ -## 1.4.102.0 *Nov 2024*--* Don't catch async exceptions in internal functions wrt https://github.com/haskell/os-string/issues/22--## 1.4.101.0 *Jan 2024*+## 1.4.200.0 *Jul 2023* -* Backport bugfix for [`splitFileName`](https://github.com/haskell/filepath/issues/219) on windows+* deprecate `OsString` modules ## 1.4.100.4 *Jul 2023*
filepath.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: filepath-version: 1.4.102.0+version: 1.4.200.0 -- NOTE: Don't forget to update ./changelog.md license: BSD-3-Clause@@ -103,7 +103,7 @@ default-language: Haskell2010 build-depends:- , base >=4.9 && <4.22+ , base >=4.9 && <4.20 , bytestring >=0.11.3.0 , deepseq , exceptions
tests/filepath-equivalent-tests/TestEquiv.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE TypeApplications #-} module Main where @@ -11,6 +10,7 @@ import qualified System.FilePath.Posix as P import qualified Legacy.System.FilePath.Windows as LW import qualified Legacy.System.FilePath.Posix as LP+import Data.Char (isAsciiLower, isAsciiUpper) main :: IO ()@@ -189,7 +189,14 @@ ) , ( "normalise (windows)"- , property $ \p -> W.normalise p == LW.normalise p+ , property $ \p -> case p of+ (l:':':rs)+ -- new filepath normalises "a:////////" to "A:\\"+ -- see https://github.com/haskell/filepath/commit/cb4890aa03a5ee61f16f7a08dd2d964fffffb385+ | isAsciiLower l || isAsciiUpper l+ , let (seps, path) = span LW.isPathSeparator rs+ , length seps > 1 -> let np = l : ':' : LW.pathSeparator : path in W.normalise np == LW.normalise np+ _ -> W.normalise p == LW.normalise p ) , ( "equalFilePath (windows)"
tests/filepath-tests/TestGen.hs view
@@ -458,8 +458,6 @@ ,("AFP_W.splitFileName (\"c:\") == ((\"c:\"), (\"\"))", property $ AFP_W.splitFileName ("c:") == (("c:"), (""))) ,("W.splitFileName \"\\\\\\\\?\\\\A:\\\\fred\" == (\"\\\\\\\\?\\\\A:\\\\\", \"fred\")", property $ W.splitFileName "\\\\?\\A:\\fred" == ("\\\\?\\A:\\", "fred")) ,("AFP_W.splitFileName (\"\\\\\\\\?\\\\A:\\\\fred\") == ((\"\\\\\\\\?\\\\A:\\\\\"), (\"fred\"))", property $ AFP_W.splitFileName ("\\\\?\\A:\\fred") == (("\\\\?\\A:\\"), ("fred")))- ,("W.splitFileName \"\\\\\\\\?\\\\A:\" == (\"\\\\\\\\?\\\\A:\", \"\")", property $ W.splitFileName "\\\\?\\A:" == ("\\\\?\\A:", ""))- ,("AFP_W.splitFileName (\"\\\\\\\\?\\\\A:\") == ((\"\\\\\\\\?\\\\A:\"), (\"\"))", property $ AFP_W.splitFileName ("\\\\?\\A:") == (("\\\\?\\A:"), (""))) ,("P.replaceFileName \"/directory/other.txt\" \"file.ext\" == \"/directory/file.ext\"", property $ P.replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext") ,("W.replaceFileName \"/directory/other.txt\" \"file.ext\" == \"/directory/file.ext\"", property $ W.replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext") ,("AFP_P.replaceFileName (\"/directory/other.txt\") (\"file.ext\") == (\"/directory/file.ext\")", property $ AFP_P.replaceFileName ("/directory/other.txt") ("file.ext") == ("/directory/file.ext"))