start converting from System.Directory to System.OsPath

This is the start of a long road, got the first few files to compile
after this large change.

Sponsored-by: mycroft
This commit is contained in:
Joey Hess 2025-01-23 10:22:06 -04:00
parent d46504e51e
commit 05bdce328d
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
8 changed files with 185 additions and 47 deletions

View file

@ -11,6 +11,7 @@ import Utility.SafeCommand
import Utility.Env.Basic import Utility.Env.Basic
import qualified Git.Version import qualified Git.Version
import Utility.SystemDirectory import Utility.SystemDirectory
import Utility.OsPath
import Control.Monad import Control.Monad
import Control.Applicative import Control.Applicative
@ -91,11 +92,11 @@ getSshConnectionCaching = Config "sshconnectioncaching" . BoolConfig <$>
setup :: IO () setup :: IO ()
setup = do setup = do
createDirectoryIfMissing True tmpDir createDirectoryIfMissing True (toOsPath tmpDir)
writeFile testFile "test file contents" writeFile testFile "test file contents"
cleanup :: IO () cleanup :: IO ()
cleanup = removeDirectoryRecursive tmpDir cleanup = removeDirectoryRecursive (toOsPath tmpDir)
run :: [TestCase] -> IO () run :: [TestCase] -> IO ()
run ts = do run ts = do

View file

@ -8,6 +8,7 @@ import Utility.Path
import Utility.Monad import Utility.Monad
import Utility.SafeCommand import Utility.SafeCommand
import Utility.SystemDirectory import Utility.SystemDirectory
import Utility.OsPath
import System.IO import System.IO
import System.FilePath import System.FilePath
@ -106,7 +107,7 @@ findCmdPath k command = do
where where
find d = find d =
let f = d </> command let f = d </> command
in ifM (doesFileExist f) ( return (Just f), return Nothing ) in ifM (doesFileExist (toOsPath f)) ( return (Just f), return Nothing )
quiet :: String -> String quiet :: String -> String
quiet s = s ++ " >/dev/null 2>&1" quiet s = s ++ " >/dev/null 2>&1"

View file

@ -73,4 +73,4 @@ writeVersion ver = catchMaybeIO (F.readFile' f) >>= \case
, "" , ""
] ]
footer = [] footer = []
f = toOsPath "Build/Version" f = literalOsPath "Build/Version"

View file

@ -89,21 +89,44 @@ openTempFile p s = do
#endif #endif
#else #else
-- When not building with OsPath, export FilePath versions -- When not building with OsPath, export RawFilePath versions
-- instead. However, functions still use ByteString for the -- instead.
-- file content in that case, unlike the Strings used by the Prelude.
import Utility.OsPath import Utility.OsPath
import System.IO (withFile, openFile, openTempFile, IO) import Utility.FileSystemEncoding
import System.IO (IO, Handle, IOMode)
import Prelude ((.), return)
import qualified System.IO import qualified System.IO
import Data.ByteString.Lazy (readFile, writeFile, appendFile)
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
withFile :: OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile = System.IO.withFile . fromRawFilePath
openFile :: OsPath -> IOMode -> IO Handle
openFile = System.IO.openFile . fromRawFilePath
readFile :: OsPath -> IO L.ByteString
readFile = L.readFile . fromRawFilePath
readFile' :: OsPath -> IO B.ByteString readFile' :: OsPath -> IO B.ByteString
readFile' = B.readFile readFile' = B.readFile . fromRawFilePath
writeFile :: OsPath -> L.ByteString -> IO ()
writeFile = L.writeFile . fromRawFilePath
writeFile' :: OsPath -> B.ByteString -> IO () writeFile' :: OsPath -> B.ByteString -> IO ()
writeFile' = B.writeFile writeFile' = B.writeFile . fromRawFilePath
appendFile :: OsPath -> L.ByteString -> IO ()
appendFile = L.appendFile . fromRawFilePath
appendFile' :: OsPath -> B.ByteString -> IO () appendFile' :: OsPath -> B.ByteString -> IO ()
appendFile' = B.appendFile appendFile' = B.appendFile . fromRawFilePath
openTempFile :: OsPath -> OsPath -> IO (OsPath, Handle)
openTempFile p s = do
(t, h) <- System.IO.openTempFile
(fromRawFilePath p)
(fromRawFilePath s)
return (toRawFilePath t, h)
#endif #endif

View file

@ -46,7 +46,6 @@ moveFile src dest = tryIO (R.rename src dest) >>= onrename
rethrow = throwM e rethrow = throwM e
mv tmp () = do mv tmp () = do
let tmp' = fromRawFilePath (fromOsPath tmp)
-- copyFile is likely not as optimised as -- copyFile is likely not as optimised as
-- the mv command, so we'll use the command. -- the mv command, so we'll use the command.
-- --
@ -59,18 +58,18 @@ moveFile src dest = tryIO (R.rename src dest) >>= onrename
ok <- copyright =<< boolSystem "mv" ok <- copyright =<< boolSystem "mv"
[ Param "-f" [ Param "-f"
, Param (fromRawFilePath src) , Param (fromRawFilePath src)
, Param tmp' , Param (fromRawFilePath (fromOsPath tmp))
] ]
let e' = e let e' = e
#else #else
r <- tryIO $ copyFile (fromRawFilePath src) tmp' r <- tryIO $ copyFile src tmp
let (ok, e') = case r of let (ok, e') = case r of
Left err -> (False, err) Left err -> (False, err)
Right _ -> (True, e) Right _ -> (True, e)
#endif #endif
unless ok $ do unless ok $ do
-- delete any partial -- delete any partial
_ <- tryIO $ removeFile tmp' _ <- tryIO $ removeFile tmp
throwM e' throwM e'
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS

View file

@ -7,51 +7,68 @@
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
{-# LANGUAGE PackageImports #-} {-# LANGUAGE PackageImports #-}
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
{-# OPTIONS_GHC -fno-warn-tabs #-} {-# OPTIONS_GHC -fno-warn-tabs #-}
module Utility.OsPath ( module Utility.OsPath (
OsPath, OsPath,
OsString, OsString,
literalOsPath,
toOsPath, toOsPath,
fromOsPath, fromOsPath,
) where ) where
import Utility.FileSystemEncoding import Utility.FileSystemEncoding
#ifdef WITH_OSPATH #ifdef WITH_OSPATH
import System.OsPath import System.OsPath
import "os-string" System.OsString.Internal.Types import "os-string" System.OsString.Internal.Types
import qualified Data.ByteString.Short as S import qualified Data.ByteString.Short as S
#else
import qualified Data.ByteString as S
#endif
class OsPathConv t where
toOsPath :: t -> OsPath
fromOsPath :: OsPath -> t
instance OsPathConv FilePath where
toOsPath = toOsPath . toRawFilePath
fromOsPath = fromRawFilePath . fromOsPath
{- Used for string constants. -}
literalOsPath :: String -> OsPath
literalOsPath = toOsPath
#ifdef WITH_OSPATH
instance OsPathConv RawFilePath where
toOsPath = bytesToOsPath
fromOsPath = bytesFromOsPath
{- Unlike System.OsString.fromBytes, on Windows this does not ensure a {- Unlike System.OsString.fromBytes, on Windows this does not ensure a
- valid USC-2LE encoding. The input ByteString must be in a valid encoding - valid USC-2LE encoding. The input ByteString must be in a valid encoding
- already or uses of the OsPath will fail. -} - already or uses of the OsPath will fail. -}
toOsPath :: RawFilePath -> OsPath bytesToOsPath :: RawFilePath -> OsPath
#if defined(mingw32_HOST_OS) #if defined(mingw32_HOST_OS)
toOsPath = OsString . WindowsString . S.toShort bytesToOsPath = OsString . WindowsString . S.toShort
#else #else
toOsPath = OsString . PosixString . S.toShort bytesToOsPath = OsString . PosixString . S.toShort
#endif #endif
fromOsPath :: OsPath -> RawFilePath bytesFromOsPath :: OsPath -> RawFilePath
#if defined(mingw32_HOST_OS) #if defined(mingw32_HOST_OS)
fromOsPath = S.fromShort . getWindowsString . getOsString bytesFromOsPath = S.fromShort . getWindowsString . getOsString
#else #else
fromOsPath = S.fromShort . getPosixString . getOsString bytesFromOsPath = S.fromShort . getPosixString . getOsString
#endif #endif
#else #else
{- When not building with WITH_OSPATH, use FilePath. This allows {- When not building with WITH_OSPATH, use RawFilePath.
- using functions from legacy FilePath libraries interchangeably with
- newer OsPath libraries.
-} -}
type OsPath = FilePath type OsPath = RawFilePath
type OsString = String type OsString = S.ByteString
toOsPath :: RawFilePath -> OsPath instance OsPathConv RawFilePath where
toOsPath = fromRawFilePath toOsPath = id
fromOsPath = id
fromOsPath :: OsPath -> RawFilePath
fromOsPath = toRawFilePath
#endif #endif

View file

@ -28,7 +28,11 @@ module Utility.Path (
) where ) where
import System.FilePath.ByteString import System.FilePath.ByteString
import qualified System.FilePath as P #ifdef WITH_OSPATH
import qualified System.OsPath as P
#else
import qualified System.FilePath.ByteString as P
#endif
import qualified Data.ByteString as B import qualified Data.ByteString as B
import Data.List import Data.List
import Data.Maybe import Data.Maybe
@ -40,6 +44,7 @@ import Author
import Utility.Monad import Utility.Monad
import Utility.SystemDirectory import Utility.SystemDirectory
import Utility.Exception import Utility.Exception
import Utility.OsPath
#ifdef mingw32_HOST_OS #ifdef mingw32_HOST_OS
import Data.Char import Data.Char
@ -251,15 +256,16 @@ inSearchPath command = isJust <$> searchPath command
- -
- Note that this will find commands in PATH that are not executable. - Note that this will find commands in PATH that are not executable.
-} -}
searchPath :: String -> IO (Maybe FilePath) searchPath :: String -> IO (Maybe OsPath)
searchPath command searchPath command
| P.isAbsolute command = copyright $ check command | P.isAbsolute command' = copyright $ check command'
| otherwise = P.getSearchPath >>= getM indir | otherwise = getSearchPath >>= getM indir . map toOsPath
where where
indir d = check $ d P.</> command command' = toOsPath command
indir d = check (d P.</> command')
check f = firstM doesFileExist check f = firstM doesFileExist
#ifdef mingw32_HOST_OS #ifdef mingw32_HOST_OS
[f, f ++ ".exe"] [f, f <> ".exe"]
#else #else
[f] [f]
#endif #endif
@ -270,10 +276,10 @@ searchPath command
- -
- Note that this will find commands in PATH that are not executable. - Note that this will find commands in PATH that are not executable.
-} -}
searchPathContents :: (FilePath -> Bool) -> IO [FilePath] searchPathContents :: (OsPath -> Bool) -> IO [OsPath]
searchPathContents p = searchPathContents p =
filterM doesFileExist filterM doesFileExist
=<< (concat <$> (P.getSearchPath >>= mapM go)) =<< (concat <$> (getSearchPath >>= mapM (go . toOsPath)))
where where
go d = map (d P.</>) . filter p go d = map (d P.</>) . filter p
<$> catchDefaultIO [] (getDirectoryContents d) <$> catchDefaultIO [] (getDirectoryContents d)

View file

@ -1,16 +1,107 @@
{- System.Directory without its conflicting isSymbolicLink and getFileSize. {- System.Directory wrapped to use OsPath.
-
- getFileSize is omitted, use Utility.FileSize instead
- -
- Copyright 2016 Joey Hess <id@joeyh.name> - Copyright 2016 Joey Hess <id@joeyh.name>
- -
- License: BSD-2-clause - License: BSD-2-clause
-} -}
-- Disable warnings because only some versions of System.Directory export {-# LANGUAGE CPP #-}
-- isSymbolicLink. {-# OPTIONS_GHC -fno-warn-tabs #-}
{-# OPTIONS_GHC -fno-warn-tabs -w #-}
module Utility.SystemDirectory ( module Utility.SystemDirectory (
module System.Directory createDirectory,
createDirectoryIfMissing,
removeDirectory,
removeDirectoryRecursive,
removePathForcibly,
renameDirectory,
listDirectory,
getDirectoryContents,
getCurrentDirectory,
setCurrentDirectory,
withCurrentDirectory,
getTemporaryDirectory,
removeFile,
renameFile,
renamePath,
copyFile,
canonicalizePath,
doesPathExist,
doesFileExist,
doesDirectoryExist,
getModificationTime,
) where ) where
import System.Directory hiding (isSymbolicLink, getFileSize) #ifdef WITH_OSPATH
import System.Directory.OsPath
#else
import qualified System.Directory as X
import Data.Time.Clock (UTCTime)
import Utility.OsPath
import Utility.FileSystemEncoding
createDirectory :: OsPath -> IO ()
createDirectory = X.createDirectory . fromRawFilePath
createDirectoryIfMissing :: Bool -> OsPath -> IO ()
createDirectoryIfMissing b = X.createDirectoryIfMissing b . fromRawFilePath
removeDirectory :: OsPath -> IO ()
removeDirectory = X.removeDirectory . fromRawFilePath
removeDirectoryRecursive :: OsPath -> IO ()
removeDirectoryRecursive = X.removeDirectoryRecursive . fromRawFilePath
removePathForcibly :: OsPath -> IO ()
removePathForcibly = X.removePathForcibly . fromRawFilePath
renameDirectory :: OsPath -> OsPath -> IO ()
renameDirectory a b = X.renameDirectory (fromRawFilePath a) (fromRawFilePath b)
listDirectory :: OsPath -> IO [OsPath]
listDirectory p = map toRawFilePath <$> X.listDirectory (fromRawFilePath p)
getDirectoryContents :: OsPath -> IO [OsPath]
getDirectoryContents p = map toRawFilePath <$> X.getDirectoryContents (fromRawFilePath p)
getCurrentDirectory :: IO OsPath
getCurrentDirectory = toRawFilePath <$> X.getCurrentDirectory
setCurrentDirectory :: OsPath -> IO ()
setCurrentDirectory = X.setCurrentDirectory . fromRawFilePath
withCurrentDirectory :: OsPath -> IO a -> IO a
withCurrentDirectory = X.withCurrentDirectory . fromRawFilePath
getTemporaryDirectory :: IO OsPath
getTemporaryDirectory = toRawFilePath <$> X.getTemporaryDirectory
removeFile :: OsPath -> IO ()
removeFile = X.removeFile . fromRawFilePath
renameFile :: OsPath -> OsPath -> IO ()
renameFile a b = X.renameFile (fromRawFilePath a) (fromRawFilePath b)
renamePath :: OsPath -> OsPath -> IO ()
renamePath a b = X.renamePath (fromRawFilePath a) (fromRawFilePath b)
copyFile :: OsPath -> OsPath -> IO ()
copyFile a b = X.copyFile (fromRawFilePath a) (fromRawFilePath b)
canonicalizePath :: OsPath -> IO OsPath
canonicalizePath p = toRawFilePath <$> X.canonicalizePath (fromRawFilePath p)
doesPathExist :: OsPath -> IO Bool
doesPathExist = X.doesPathExist . fromRawFilePath
doesFileExist :: OsPath -> IO Bool
doesFileExist = X.doesFileExist . fromRawFilePath
doesDirectoryExist :: OsPath -> IO Bool
doesDirectoryExist = X.doesDirectoryExist . fromRawFilePath
getModificationTime :: OsPath -> IO UTCTime
getModificationTime = X.getModificationTime . fromRawFilePath
#endif