add file-io to build-depends when building with OsPath flag

Partly converted code to use functions from it, though more remain
unconverted. Most of withFile and openFile now use it.
This commit is contained in:
Joey Hess 2025-01-21 14:26:04 -04:00
parent 85efc13e3a
commit 1faa3af9cd
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
20 changed files with 178 additions and 68 deletions

View file

@ -12,6 +12,11 @@
module Utility.Directory where
#ifdef WITH_OSPATH
import System.Directory.OsPath
#else
import Utility.SystemDirectory
#endif
import Control.Monad
import System.PosixCompat.Files (isDirectory, isSymbolicLink)
import Control.Applicative
@ -20,40 +25,24 @@ import qualified System.FilePath.ByteString as P
import Data.Maybe
import Prelude
import Utility.OsPath
import Utility.Exception
import Utility.Monad
import Utility.FileSystemEncoding
import qualified Utility.RawFilePath as R
#ifdef WITH_OSPATH
import Utility.OsPath
import qualified System.Directory.OsPath as OP
#else
import Utility.SystemDirectory
#endif
dirCruft :: R.RawFilePath -> Bool
dirCruft "." = True
dirCruft ".." = True
dirCruft _ = False
dirCruft' :: R.RawFilePath -> Bool
dirCruft' "." = True
dirCruft' ".." = True
dirCruft' _ = False
{- Lists the contents of a directory.
- Unlike getDirectoryContents, paths are not relative to the directory. -}
dirContents :: RawFilePath -> IO [RawFilePath]
#ifdef WITH_OSPATH
dirContents d = map (\p -> d P.</> fromOsPath p)
<$> OP.listDirectory (toOsPath d)
#else
dirContents d =
map (\p -> d P.</> toRawFilePath p)
. filter (not . dirCruft . toRawFilePath)
<$> getDirectoryContents (fromRawFilePath d)
#endif
map (\p -> d P.</> fromOsPath p)
. filter (not . dirCruft . fromOsPath)
<$> getDirectoryContents (toOsPath d)
{- Gets files in a directory, and then its subdirectories, recursively,
- and lazily.
@ -102,11 +91,7 @@ dirContentsRecursiveSkipping skipdir followsubdirsymlinks topdir
(Just s)
| isDirectory s -> recurse
| isSymbolicLink s && followsubdirsymlinks ->
#ifdef WITH_OSPATH
ifM (OP.doesDirectoryExist (toOsPath entry))
#else
ifM (doesDirectoryExist (fromRawFilePath entry))
#endif
ifM (doesDirectoryExist (toOsPath entry))
( recurse
, skip
)

103
Utility/FileIO.hs Normal file
View file

@ -0,0 +1,103 @@
{- File IO on OsPaths.
-
- Since Prelude exports many of these as well, this needs to be imported
- qualified.
-
- Copyright 2025 Joey Hess <id@joeyh.name>
-
- License: BSD-2-clause
-}
{-# OPTIONS_GHC -fno-warn-tabs #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Utility.FileIO
(
withFile,
openFile,
readFile,
readFile',
writeFile,
writeFile',
appendFile,
appendFile',
) where
#ifdef WITH_OSPATH
#ifndef mingw32_HOST_OS
import System.File.OsPath
#else
-- On Windows, System.File.OsPath does not handle UNC-style conversion itself,
-- so that has to be done when calling it. See
-- https://github.com/haskell/file-io/issues/39
import Utility.Path.Windows
import Utility.OsPath
import System.IO (IO, Handle, IOMode)
import System.OsPath (OsPath)
import qualified System.File.OsPath as O
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Control.Applicative
withFile :: OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile f m a = do
f' <- toOsPath <$> convertToWindowsNativeNamespace (fromOsPath f)
O.withFile f' m a
openFile :: OsPath -> IOMode -> IO Handle
openFile f m = do
f' <- toOsPath <$> convertToWindowsNativeNamespace (fromOsPath f)
O.openFile f' m
readFile :: OsPath -> IO L.ByteString
readFile f = do
f' <- toOsPath <$> convertToWindowsNativeNamespace (fromOsPath f)
O.readFile f'
readFile' :: OsPath -> IO B.ByteString
readFile' f = do
f' <- toOsPath <$> convertToWindowsNativeNamespace (fromOsPath f)
O.readFile' f'
writeFile :: OsPath -> L.ByteString -> IO ()
writeFile f b = do
f' <- toOsPath <$> convertToWindowsNativeNamespace (fromOsPath f)
O.writeFile f' b
writeFile' :: OsPath -> B.ByteString -> IO ()
writeFile' f b = do
f' <- toOsPath <$> convertToWindowsNativeNamespace (fromOsPath f)
O.writeFile' f' b
appendFile :: OsPath -> L.ByteString -> IO ()
appendFile f b = do
f' <- toOsPath <$> convertToWindowsNativeNamespace (fromOsPath f)
O.appendFile f' b
appendFile' :: OsPath -> B.ByteString -> IO ()
appendFile' f b = do
f' <- toOsPath <$> convertToWindowsNativeNamespace (fromOsPath f)
O.appendFile' f' b
#endif
#else
-- When not building with OsPath, export FilePath versions
-- instead. However, functions still use ByteString for the
-- file content in that case, unlike the Strings used by the Prelude.
import Utility.OsPath
import System.IO (withFile, openFile, IO)
import Data.ByteString.Lazy (readFile, writeFile, appendFile)
import qualified Data.ByteString as B
readFile' :: OsPath -> IO B.ByteString
readFile' = B.readFile
writeFile' :: OsPath -> B.ByteString -> IO ()
writeFile' = B.writeFile
appendFile' :: OsPath -> B.ByteString -> IO ()
appendFile' = B.appendFile
#endif

View file

@ -27,6 +27,8 @@ import Control.Monad.Catch
import Utility.Exception
import Utility.FileSystemEncoding
import qualified Utility.RawFilePath as R
import qualified Utility.FileIO as F
import Utility.OsPath
{- Applies a conversion function to a file's mode. -}
modifyFileMode :: RawFilePath -> (FileMode -> FileMode) -> IO ()
@ -178,7 +180,7 @@ writeFileProtected' :: RawFilePath -> (Handle -> IO ()) -> IO ()
writeFileProtected' file writer = bracket setup cleanup writer
where
setup = do
h <- protectedOutput $ openFile (fromRawFilePath file) WriteMode
h <- protectedOutput $ F.openFile (toOsPath file) WriteMode
void $ tryIO $ modifyFileMode file $ removeModes otherGroupModes
return h
cleanup = hClose

View file

@ -18,6 +18,8 @@ module Utility.FileSize (
import Control.Exception (bracket)
import System.IO
import Utility.FileSystemEncoding
import qualified Utility.FileIO as F
import Utility.OsPath
#else
import System.PosixCompat.Files (fileSize)
#endif
@ -36,7 +38,7 @@ getFileSize :: R.RawFilePath -> IO FileSize
#ifndef mingw32_HOST_OS
getFileSize f = fmap (fromIntegral . fileSize) (R.getFileStatus f)
#else
getFileSize f = bracket (openFile (fromRawFilePath f) ReadMode) hClose hFileSize
getFileSize f = bracket (F.openFile (toOsPath f) ReadMode) hClose hFileSize
#endif
{- Gets the size of the file, when its FileStatus is already known.

View file

@ -13,6 +13,9 @@ module Utility.HtmlDetect (
) where
import Author
import qualified Utility.FileIO as F
import Utility.RawFilePath
import Utility.OsPath
import Text.HTML.TagSoup
import System.IO
@ -57,8 +60,8 @@ isHtmlBs = isHtml . B8.unpack
-- It would be equivalent to use isHtml <$> readFile file,
-- but since that would not read all of the file, the handle
-- would remain open until it got garbage collected sometime later.
isHtmlFile :: FilePath -> IO Bool
isHtmlFile file = withFile file ReadMode $ \h ->
isHtmlFile :: RawFilePath -> IO Bool
isHtmlFile file = F.withFile (toOsPath file) ReadMode $ \h ->
isHtmlBs <$> B.hGet h htmlPrefixLength
-- | How much of the beginning of a html document is needed to detect it.

View file

@ -11,10 +11,9 @@
module Utility.OsPath where
import Utility.FileSystemEncoding
#ifdef WITH_OSPATH
import Utility.RawFilePath
import System.OsPath
import "os-string" System.OsString.Internal.Types
import qualified Data.ByteString.Short as S
@ -36,4 +35,15 @@ fromOsPath = S.fromShort . getWindowsString . getOsString
fromOsPath = S.fromShort . getPosixString . getOsString
#endif
#endif /* WITH_OSPATH */
#else
{- When not building with WITH_OSPATH, use FilePath. This allows
- using functions from legacy FilePath libraries interchangeably with
- newer OsPath libraries.
- -}
type OsPath = FilePath
toOsPath :: RawFilePath -> OsPath
toOsPath = fromRawFilePath
fromOsPath :: OsPath -> RawFilePath
fromOsPath = toRawFilePath
#endif