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:
parent
85efc13e3a
commit
1faa3af9cd
20 changed files with 178 additions and 68 deletions
|
@ -27,6 +27,7 @@ import Annex.BranchState
|
||||||
import Types.BranchState
|
import Types.BranchState
|
||||||
import Utility.Directory.Stream
|
import Utility.Directory.Stream
|
||||||
import qualified Utility.RawFilePath as R
|
import qualified Utility.RawFilePath as R
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
|
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
|
@ -92,7 +93,7 @@ setJournalFile _jl ru file content = withOtherTmp $ \tmp -> do
|
||||||
-- journal file is written atomically
|
-- journal file is written atomically
|
||||||
let jfile = journalFile file
|
let jfile = journalFile file
|
||||||
let tmpfile = tmp P.</> jfile
|
let tmpfile = tmp P.</> jfile
|
||||||
liftIO $ withFile (fromRawFilePath tmpfile) WriteMode $ \h ->
|
liftIO $ F.withFile (toOsPath tmpfile) WriteMode $ \h ->
|
||||||
writeJournalHandle h content
|
writeJournalHandle h content
|
||||||
let dest = jd P.</> jfile
|
let dest = jd P.</> jfile
|
||||||
let mv = do
|
let mv = do
|
||||||
|
@ -133,7 +134,7 @@ checkCanAppendJournalFile _jl ru file = do
|
||||||
-}
|
-}
|
||||||
appendJournalFile :: Journalable content => JournalLocked -> AppendableJournalFile -> content -> Annex ()
|
appendJournalFile :: Journalable content => JournalLocked -> AppendableJournalFile -> content -> Annex ()
|
||||||
appendJournalFile _jl (AppendableJournalFile (jd, jfile)) content = do
|
appendJournalFile _jl (AppendableJournalFile (jd, jfile)) content = do
|
||||||
let write = liftIO $ withFile (fromRawFilePath jfile) ReadWriteMode $ \h -> do
|
let write = liftIO $ F.withFile (toOsPath jfile) ReadWriteMode $ \h -> do
|
||||||
sz <- hFileSize h
|
sz <- hFileSize h
|
||||||
when (sz /= 0) $ do
|
when (sz /= 0) $ do
|
||||||
hSeek h SeekFromEnd (-1)
|
hSeek h SeekFromEnd (-1)
|
||||||
|
|
|
@ -38,6 +38,7 @@ import Utility.Tmp.Dir
|
||||||
import Utility.CopyFile
|
import Utility.CopyFile
|
||||||
import qualified Database.Keys.Handle
|
import qualified Database.Keys.Handle
|
||||||
import qualified Utility.RawFilePath as R
|
import qualified Utility.RawFilePath as R
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
|
|
||||||
import qualified Data.ByteString as S
|
import qualified Data.ByteString as S
|
||||||
import qualified Data.ByteString.Char8 as S8
|
import qualified Data.ByteString.Char8 as S8
|
||||||
|
@ -87,7 +88,7 @@ getAnnexLinkTarget' file coresymlinks = if coresymlinks
|
||||||
|
|
||||||
probesymlink = R.readSymbolicLink file
|
probesymlink = R.readSymbolicLink file
|
||||||
|
|
||||||
probefilecontent = withFile (fromRawFilePath file) ReadMode $ \h -> do
|
probefilecontent = F.withFile (toOsPath file) ReadMode $ \h -> do
|
||||||
s <- S.hGet h maxSymlinkSz
|
s <- S.hGet h maxSymlinkSz
|
||||||
-- If we got the full amount, the file is too large
|
-- If we got the full amount, the file is too large
|
||||||
-- to be a symlink target.
|
-- to be a symlink target.
|
||||||
|
@ -434,7 +435,7 @@ maxSymlinkSz = 8192
|
||||||
isPointerFile :: RawFilePath -> IO (Maybe Key)
|
isPointerFile :: RawFilePath -> IO (Maybe Key)
|
||||||
isPointerFile f = catchDefaultIO Nothing $
|
isPointerFile f = catchDefaultIO Nothing $
|
||||||
#if defined(mingw32_HOST_OS)
|
#if defined(mingw32_HOST_OS)
|
||||||
withFile (fromRawFilePath f) ReadMode readhandle
|
F.withFile (toOsPath f) ReadMode readhandle
|
||||||
#else
|
#else
|
||||||
#if MIN_VERSION_unix(2,8,0)
|
#if MIN_VERSION_unix(2,8,0)
|
||||||
let open = do
|
let open = do
|
||||||
|
@ -445,7 +446,7 @@ isPointerFile f = catchDefaultIO Nothing $
|
||||||
#else
|
#else
|
||||||
ifM (isSymbolicLink <$> R.getSymbolicLinkStatus f)
|
ifM (isSymbolicLink <$> R.getSymbolicLinkStatus f)
|
||||||
( return Nothing
|
( return Nothing
|
||||||
, withFile (fromRawFilePath f) ReadMode readhandle
|
, F.withFile (toOsPath f) ReadMode readhandle
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,6 +30,7 @@ import Utility.Tmp.Dir
|
||||||
import Utility.Metered
|
import Utility.Metered
|
||||||
import Git.Types
|
import Git.Types
|
||||||
import qualified Database.Export as Export
|
import qualified Database.Export as Export
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
#ifndef mingw32_HOST_OS
|
#ifndef mingw32_HOST_OS
|
||||||
import Utility.OpenFile
|
import Utility.OpenFile
|
||||||
#endif
|
#endif
|
||||||
|
@ -184,7 +185,7 @@ proxySpecialRemote protoversion r ihdl ohdl owaitv oclosedv mexportdb = go
|
||||||
-- the client, to avoid bad content
|
-- the client, to avoid bad content
|
||||||
-- being stored in the special remote.
|
-- being stored in the special remote.
|
||||||
iv <- startVerifyKeyContentIncrementally Remote.AlwaysVerify k
|
iv <- startVerifyKeyContentIncrementally Remote.AlwaysVerify k
|
||||||
h <- liftIO $ openFile (fromRawFilePath tmpfile) WriteMode
|
h <- liftIO $ F.openFile (toOsPath tmpfile) WriteMode
|
||||||
let nuketmp = liftIO $ removeWhenExistsWith removeFile (fromRawFilePath tmpfile)
|
let nuketmp = liftIO $ removeWhenExistsWith removeFile (fromRawFilePath tmpfile)
|
||||||
gotall <- liftIO $ receivetofile iv h len
|
gotall <- liftIO $ receivetofile iv h len
|
||||||
liftIO $ hClose h
|
liftIO $ hClose h
|
||||||
|
|
|
@ -3,6 +3,7 @@ git-annex (10.20250116) UNRELEASED; urgency=medium
|
||||||
* Support help.autocorrect settings "prompt", "never", and "immediate".
|
* Support help.autocorrect settings "prompt", "never", and "immediate".
|
||||||
* Allow setting remote.foo.annex-tracking-branch to a branch name
|
* Allow setting remote.foo.annex-tracking-branch to a branch name
|
||||||
that contains "/", as long as it's not a remote tracking branch.
|
that contains "/", as long as it's not a remote tracking branch.
|
||||||
|
* Added OsPath build flag, which speeds up git-annex's operations on files.
|
||||||
|
|
||||||
-- Joey Hess <id@joeyh.name> Mon, 20 Jan 2025 10:24:51 -0400
|
-- Joey Hess <id@joeyh.name> Mon, 20 Jan 2025 10:24:51 -0400
|
||||||
|
|
||||||
|
|
|
@ -353,7 +353,7 @@ downloadWeb addunlockedmatcher o url urlinfo file =
|
||||||
urlkey = addSizeUrlKey urlinfo $ Backend.URL.fromUrl url Nothing (verifiableOption o)
|
urlkey = addSizeUrlKey urlinfo $ Backend.URL.fromUrl url Nothing (verifiableOption o)
|
||||||
downloader f p = Url.withUrlOptions $ downloadUrl False urlkey p Nothing [url] f
|
downloader f p = Url.withUrlOptions $ downloadUrl False urlkey p Nothing [url] f
|
||||||
go Nothing = return Nothing
|
go Nothing = return Nothing
|
||||||
go (Just (tmp, backend)) = ifM (useYoutubeDl o <&&> liftIO (isHtmlFile (fromRawFilePath tmp)))
|
go (Just (tmp, backend)) = ifM (useYoutubeDl o <&&> liftIO (isHtmlFile tmp))
|
||||||
( tryyoutubedl tmp backend
|
( tryyoutubedl tmp backend
|
||||||
, normalfinish tmp backend
|
, normalfinish tmp backend
|
||||||
)
|
)
|
||||||
|
|
|
@ -45,6 +45,7 @@ import qualified Database.Fsck as FsckDb
|
||||||
import Types.CleanupActions
|
import Types.CleanupActions
|
||||||
import Types.Key
|
import Types.Key
|
||||||
import qualified Utility.RawFilePath as R
|
import qualified Utility.RawFilePath as R
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
|
|
||||||
import Data.Time.Clock.POSIX
|
import Data.Time.Clock.POSIX
|
||||||
import System.Posix.Types (EpochTime)
|
import System.Posix.Types (EpochTime)
|
||||||
|
@ -678,7 +679,7 @@ recordStartTime u = do
|
||||||
f <- fromRepo (gitAnnexFsckState u)
|
f <- fromRepo (gitAnnexFsckState u)
|
||||||
createAnnexDirectory $ parentDir f
|
createAnnexDirectory $ parentDir f
|
||||||
liftIO $ removeWhenExistsWith R.removeLink f
|
liftIO $ removeWhenExistsWith R.removeLink f
|
||||||
liftIO $ withFile (fromRawFilePath f) WriteMode $ \h -> do
|
liftIO $ F.withFile (toOsPath f) WriteMode $ \h -> do
|
||||||
#ifndef mingw32_HOST_OS
|
#ifndef mingw32_HOST_OS
|
||||||
t <- modificationTime <$> R.getFileStatus f
|
t <- modificationTime <$> R.getFileStatus f
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -33,5 +33,6 @@ import Utility.FileSize as X
|
||||||
import Utility.Network as X
|
import Utility.Network as X
|
||||||
import Utility.Split as X
|
import Utility.Split as X
|
||||||
import Utility.FileSystemEncoding as X
|
import Utility.FileSystemEncoding as X
|
||||||
|
import Utility.OsPath as X
|
||||||
|
|
||||||
import Utility.PartialPrelude as X
|
import Utility.PartialPrelude as X
|
||||||
|
|
25
Logs/File.hs
25
Logs/File.hs
|
@ -26,6 +26,7 @@ import Annex.Perms
|
||||||
import Annex.LockFile
|
import Annex.LockFile
|
||||||
import Annex.ReplaceFile
|
import Annex.ReplaceFile
|
||||||
import Utility.Tmp
|
import Utility.Tmp
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
|
|
||||||
import qualified Data.ByteString as S
|
import qualified Data.ByteString as S
|
||||||
import qualified Data.ByteString.Char8 as S8
|
import qualified Data.ByteString.Char8 as S8
|
||||||
|
@ -52,7 +53,7 @@ withLogHandle f a = do
|
||||||
where
|
where
|
||||||
setup tmp = do
|
setup tmp = do
|
||||||
setAnnexFilePerm tmp
|
setAnnexFilePerm tmp
|
||||||
liftIO $ openFile (fromRawFilePath tmp) WriteMode
|
liftIO $ F.openFile (toOsPath tmp) WriteMode
|
||||||
cleanup h = liftIO $ hClose h
|
cleanup h = liftIO $ hClose h
|
||||||
|
|
||||||
-- | Appends a line to a log file, first locking it to prevent
|
-- | Appends a line to a log file, first locking it to prevent
|
||||||
|
@ -61,11 +62,9 @@ appendLogFile :: RawFilePath -> RawFilePath -> L.ByteString -> Annex ()
|
||||||
appendLogFile f lck c =
|
appendLogFile f lck c =
|
||||||
createDirWhenNeeded f $
|
createDirWhenNeeded f $
|
||||||
withExclusiveLock lck $ do
|
withExclusiveLock lck $ do
|
||||||
liftIO $ withFile f' AppendMode $
|
liftIO $ F.withFile (toOsPath f) AppendMode $
|
||||||
\h -> L8.hPutStrLn h c
|
\h -> L8.hPutStrLn h c
|
||||||
setAnnexFilePerm (toRawFilePath f')
|
setAnnexFilePerm f
|
||||||
where
|
|
||||||
f' = fromRawFilePath f
|
|
||||||
|
|
||||||
-- | Modifies a log file.
|
-- | Modifies a log file.
|
||||||
--
|
--
|
||||||
|
@ -93,14 +92,13 @@ modifyLogFile f lck modf = withExclusiveLock lck $ do
|
||||||
checkLogFile :: RawFilePath -> RawFilePath -> (L.ByteString -> Bool) -> Annex Bool
|
checkLogFile :: RawFilePath -> RawFilePath -> (L.ByteString -> Bool) -> Annex Bool
|
||||||
checkLogFile f lck matchf = withSharedLock lck $ bracket setup cleanup go
|
checkLogFile f lck matchf = withSharedLock lck $ bracket setup cleanup go
|
||||||
where
|
where
|
||||||
setup = liftIO $ tryWhenExists $ openFile f' ReadMode
|
setup = liftIO $ tryWhenExists $ F.openFile (toOsPath f) ReadMode
|
||||||
cleanup Nothing = noop
|
cleanup Nothing = noop
|
||||||
cleanup (Just h) = liftIO $ hClose h
|
cleanup (Just h) = liftIO $ hClose h
|
||||||
go Nothing = return False
|
go Nothing = return False
|
||||||
go (Just h) = do
|
go (Just h) = do
|
||||||
!r <- liftIO (any matchf . fileLines <$> L.hGetContents h)
|
!r <- liftIO (any matchf . fileLines <$> L.hGetContents h)
|
||||||
return r
|
return r
|
||||||
f' = fromRawFilePath f
|
|
||||||
|
|
||||||
-- | Folds a function over lines of a log file to calculate a value.
|
-- | Folds a function over lines of a log file to calculate a value.
|
||||||
calcLogFile :: RawFilePath -> RawFilePath -> t -> (L.ByteString -> t -> t) -> Annex t
|
calcLogFile :: RawFilePath -> RawFilePath -> t -> (L.ByteString -> t -> t) -> Annex t
|
||||||
|
@ -111,7 +109,7 @@ calcLogFile f lck start update =
|
||||||
calcLogFileUnsafe :: RawFilePath -> t -> (L.ByteString -> t -> t) -> Annex t
|
calcLogFileUnsafe :: RawFilePath -> t -> (L.ByteString -> t -> t) -> Annex t
|
||||||
calcLogFileUnsafe f start update = bracket setup cleanup go
|
calcLogFileUnsafe f start update = bracket setup cleanup go
|
||||||
where
|
where
|
||||||
setup = liftIO $ tryWhenExists $ openFile f' ReadMode
|
setup = liftIO $ tryWhenExists $ F.openFile (toOsPath f) ReadMode
|
||||||
cleanup Nothing = noop
|
cleanup Nothing = noop
|
||||||
cleanup (Just h) = liftIO $ hClose h
|
cleanup (Just h) = liftIO $ hClose h
|
||||||
go Nothing = return start
|
go Nothing = return start
|
||||||
|
@ -120,7 +118,6 @@ calcLogFileUnsafe f start update = bracket setup cleanup go
|
||||||
go' v (l:ls) = do
|
go' v (l:ls) = do
|
||||||
let !v' = update l v
|
let !v' = update l v
|
||||||
go' v' ls
|
go' v' ls
|
||||||
f' = fromRawFilePath f
|
|
||||||
|
|
||||||
-- | Streams lines from a log file, passing each line to the processor,
|
-- | Streams lines from a log file, passing each line to the processor,
|
||||||
-- and then empties the file at the end.
|
-- and then empties the file at the end.
|
||||||
|
@ -134,19 +131,19 @@ calcLogFileUnsafe f start update = bracket setup cleanup go
|
||||||
--
|
--
|
||||||
-- Locking is used to prevent writes to to the log file while this
|
-- Locking is used to prevent writes to to the log file while this
|
||||||
-- is running.
|
-- is running.
|
||||||
streamLogFile :: FilePath -> RawFilePath -> Annex () -> (String -> Annex ()) -> Annex ()
|
streamLogFile :: RawFilePath -> RawFilePath -> Annex () -> (String -> Annex ()) -> Annex ()
|
||||||
streamLogFile f lck finalizer processor =
|
streamLogFile f lck finalizer processor =
|
||||||
withExclusiveLock lck $ do
|
withExclusiveLock lck $ do
|
||||||
streamLogFileUnsafe f finalizer processor
|
streamLogFileUnsafe f finalizer processor
|
||||||
liftIO $ writeFile f ""
|
liftIO $ F.writeFile' (toOsPath f) mempty
|
||||||
setAnnexFilePerm (toRawFilePath f)
|
setAnnexFilePerm f
|
||||||
|
|
||||||
-- Unsafe version that does not do locking, and does not empty the file
|
-- Unsafe version that does not do locking, and does not empty the file
|
||||||
-- at the end.
|
-- at the end.
|
||||||
streamLogFileUnsafe :: FilePath -> Annex () -> (String -> Annex ()) -> Annex ()
|
streamLogFileUnsafe :: RawFilePath -> Annex () -> (String -> Annex ()) -> Annex ()
|
||||||
streamLogFileUnsafe f finalizer processor = bracketOnError setup cleanup go
|
streamLogFileUnsafe f finalizer processor = bracketOnError setup cleanup go
|
||||||
where
|
where
|
||||||
setup = liftIO $ tryWhenExists $ openFile f ReadMode
|
setup = liftIO $ tryWhenExists $ F.openFile (toOsPath f) ReadMode
|
||||||
cleanup Nothing = noop
|
cleanup Nothing = noop
|
||||||
cleanup (Just h) = liftIO $ hClose h
|
cleanup (Just h) = liftIO $ hClose h
|
||||||
go Nothing = finalizer
|
go Nothing = finalizer
|
||||||
|
|
|
@ -79,7 +79,7 @@ logMigration old new = do
|
||||||
-- | Commits a migration to the git-annex branch.
|
-- | Commits a migration to the git-annex branch.
|
||||||
commitMigration :: Annex ()
|
commitMigration :: Annex ()
|
||||||
commitMigration = do
|
commitMigration = do
|
||||||
logf <- fromRawFilePath <$> fromRepo gitAnnexMigrateLog
|
logf <- fromRepo gitAnnexMigrateLog
|
||||||
lckf <- fromRepo gitAnnexMigrateLock
|
lckf <- fromRepo gitAnnexMigrateLock
|
||||||
nv <- liftIO $ newTVarIO (0 :: Integer)
|
nv <- liftIO $ newTVarIO (0 :: Integer)
|
||||||
g <- Annex.gitRepo
|
g <- Annex.gitRepo
|
||||||
|
|
|
@ -14,6 +14,7 @@ import Git.FilePath
|
||||||
import Logs.File
|
import Logs.File
|
||||||
import Utility.InodeCache
|
import Utility.InodeCache
|
||||||
import Annex.LockFile
|
import Annex.LockFile
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
|
|
||||||
import qualified Data.ByteString as S
|
import qualified Data.ByteString as S
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
|
@ -48,21 +49,20 @@ streamRestageLog :: Annex () -> (TopFilePath -> InodeCache -> Annex ()) -> Annex
|
||||||
streamRestageLog finalizer processor = do
|
streamRestageLog finalizer processor = do
|
||||||
logf <- fromRepo gitAnnexRestageLog
|
logf <- fromRepo gitAnnexRestageLog
|
||||||
oldf <- fromRepo gitAnnexRestageLogOld
|
oldf <- fromRepo gitAnnexRestageLogOld
|
||||||
let oldf' = fromRawFilePath oldf
|
|
||||||
lckf <- fromRepo gitAnnexRestageLock
|
lckf <- fromRepo gitAnnexRestageLock
|
||||||
|
|
||||||
withExclusiveLock lckf $ liftIO $
|
withExclusiveLock lckf $ liftIO $
|
||||||
whenM (R.doesPathExist logf) $
|
whenM (R.doesPathExist logf) $
|
||||||
ifM (R.doesPathExist oldf)
|
ifM (R.doesPathExist oldf)
|
||||||
( do
|
( do
|
||||||
h <- openFile oldf' AppendMode
|
h <- F.openFile (toOsPath oldf) AppendMode
|
||||||
hPutStr h =<< readFile (fromRawFilePath logf)
|
hPutStr h =<< readFile (fromRawFilePath logf)
|
||||||
hClose h
|
hClose h
|
||||||
liftIO $ removeWhenExistsWith R.removeLink logf
|
liftIO $ removeWhenExistsWith R.removeLink logf
|
||||||
, moveFile logf oldf
|
, moveFile logf oldf
|
||||||
)
|
)
|
||||||
|
|
||||||
streamLogFileUnsafe oldf' finalizer $ \l ->
|
streamLogFileUnsafe oldf finalizer $ \l ->
|
||||||
case parseRestageLog l of
|
case parseRestageLog l of
|
||||||
Just (f, ic) -> processor f ic
|
Just (f, ic) -> processor f ic
|
||||||
Nothing -> noop
|
Nothing -> noop
|
||||||
|
|
|
@ -34,7 +34,7 @@ streamSmudged :: (Key -> TopFilePath -> Annex ()) -> Annex ()
|
||||||
streamSmudged a = do
|
streamSmudged a = do
|
||||||
logf <- fromRepo gitAnnexSmudgeLog
|
logf <- fromRepo gitAnnexSmudgeLog
|
||||||
lckf <- fromRepo gitAnnexSmudgeLock
|
lckf <- fromRepo gitAnnexSmudgeLock
|
||||||
streamLogFile (fromRawFilePath logf) lckf noop $ \l ->
|
streamLogFile logf lckf noop $ \l ->
|
||||||
case parse l of
|
case parse l of
|
||||||
Nothing -> noop
|
Nothing -> noop
|
||||||
Just (k, f) -> a k f
|
Just (k, f) -> a k f
|
||||||
|
|
|
@ -29,6 +29,7 @@ import Annex.Perms
|
||||||
import Utility.InodeCache
|
import Utility.InodeCache
|
||||||
import Annex.InodeSentinal
|
import Annex.InodeSentinal
|
||||||
import qualified Utility.RawFilePath as R
|
import qualified Utility.RawFilePath as R
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
|
|
||||||
setIndirect :: Annex ()
|
setIndirect :: Annex ()
|
||||||
setIndirect = do
|
setIndirect = do
|
||||||
|
@ -88,8 +89,8 @@ associatedFiles key = do
|
||||||
- the top of the repo. -}
|
- the top of the repo. -}
|
||||||
associatedFilesRelative :: Key -> Annex [FilePath]
|
associatedFilesRelative :: Key -> Annex [FilePath]
|
||||||
associatedFilesRelative key = do
|
associatedFilesRelative key = do
|
||||||
mapping <- fromRawFilePath <$> calcRepo (gitAnnexMapping key)
|
mapping <- calcRepo (gitAnnexMapping key)
|
||||||
liftIO $ catchDefaultIO [] $ withFile mapping ReadMode $ \h ->
|
liftIO $ catchDefaultIO [] $ F.withFile (toOsPath mapping) ReadMode $ \h ->
|
||||||
-- Read strictly to ensure the file is closed promptly
|
-- Read strictly to ensure the file is closed promptly
|
||||||
lines <$> hGetContentsStrict h
|
lines <$> hGetContentsStrict h
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
|
|
||||||
module Utility.Directory where
|
module Utility.Directory where
|
||||||
|
|
||||||
|
#ifdef WITH_OSPATH
|
||||||
|
import System.Directory.OsPath
|
||||||
|
#else
|
||||||
|
import Utility.SystemDirectory
|
||||||
|
#endif
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import System.PosixCompat.Files (isDirectory, isSymbolicLink)
|
import System.PosixCompat.Files (isDirectory, isSymbolicLink)
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
|
@ -20,40 +25,24 @@ import qualified System.FilePath.ByteString as P
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
|
import Utility.OsPath
|
||||||
import Utility.Exception
|
import Utility.Exception
|
||||||
import Utility.Monad
|
import Utility.Monad
|
||||||
import Utility.FileSystemEncoding
|
import Utility.FileSystemEncoding
|
||||||
import qualified Utility.RawFilePath as R
|
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 :: R.RawFilePath -> Bool
|
||||||
dirCruft "." = True
|
dirCruft "." = True
|
||||||
dirCruft ".." = True
|
dirCruft ".." = True
|
||||||
dirCruft _ = False
|
dirCruft _ = False
|
||||||
|
|
||||||
dirCruft' :: R.RawFilePath -> Bool
|
|
||||||
dirCruft' "." = True
|
|
||||||
dirCruft' ".." = True
|
|
||||||
dirCruft' _ = False
|
|
||||||
|
|
||||||
{- Lists the contents of a directory.
|
{- Lists the contents of a directory.
|
||||||
- Unlike getDirectoryContents, paths are not relative to the directory. -}
|
- Unlike getDirectoryContents, paths are not relative to the directory. -}
|
||||||
dirContents :: RawFilePath -> IO [RawFilePath]
|
dirContents :: RawFilePath -> IO [RawFilePath]
|
||||||
#ifdef WITH_OSPATH
|
|
||||||
dirContents d = map (\p -> d P.</> fromOsPath p)
|
|
||||||
<$> OP.listDirectory (toOsPath d)
|
|
||||||
#else
|
|
||||||
dirContents d =
|
dirContents d =
|
||||||
map (\p -> d P.</> toRawFilePath p)
|
map (\p -> d P.</> fromOsPath p)
|
||||||
. filter (not . dirCruft . toRawFilePath)
|
. filter (not . dirCruft . fromOsPath)
|
||||||
<$> getDirectoryContents (fromRawFilePath d)
|
<$> getDirectoryContents (toOsPath d)
|
||||||
#endif
|
|
||||||
|
|
||||||
{- Gets files in a directory, and then its subdirectories, recursively,
|
{- Gets files in a directory, and then its subdirectories, recursively,
|
||||||
- and lazily.
|
- and lazily.
|
||||||
|
@ -102,11 +91,7 @@ dirContentsRecursiveSkipping skipdir followsubdirsymlinks topdir
|
||||||
(Just s)
|
(Just s)
|
||||||
| isDirectory s -> recurse
|
| isDirectory s -> recurse
|
||||||
| isSymbolicLink s && followsubdirsymlinks ->
|
| isSymbolicLink s && followsubdirsymlinks ->
|
||||||
#ifdef WITH_OSPATH
|
ifM (doesDirectoryExist (toOsPath entry))
|
||||||
ifM (OP.doesDirectoryExist (toOsPath entry))
|
|
||||||
#else
|
|
||||||
ifM (doesDirectoryExist (fromRawFilePath entry))
|
|
||||||
#endif
|
|
||||||
( recurse
|
( recurse
|
||||||
, skip
|
, skip
|
||||||
)
|
)
|
||||||
|
|
103
Utility/FileIO.hs
Normal file
103
Utility/FileIO.hs
Normal 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
|
|
@ -27,6 +27,8 @@ import Control.Monad.Catch
|
||||||
import Utility.Exception
|
import Utility.Exception
|
||||||
import Utility.FileSystemEncoding
|
import Utility.FileSystemEncoding
|
||||||
import qualified Utility.RawFilePath as R
|
import qualified Utility.RawFilePath as R
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
|
import Utility.OsPath
|
||||||
|
|
||||||
{- Applies a conversion function to a file's mode. -}
|
{- Applies a conversion function to a file's mode. -}
|
||||||
modifyFileMode :: RawFilePath -> (FileMode -> FileMode) -> IO ()
|
modifyFileMode :: RawFilePath -> (FileMode -> FileMode) -> IO ()
|
||||||
|
@ -178,7 +180,7 @@ writeFileProtected' :: RawFilePath -> (Handle -> IO ()) -> IO ()
|
||||||
writeFileProtected' file writer = bracket setup cleanup writer
|
writeFileProtected' file writer = bracket setup cleanup writer
|
||||||
where
|
where
|
||||||
setup = do
|
setup = do
|
||||||
h <- protectedOutput $ openFile (fromRawFilePath file) WriteMode
|
h <- protectedOutput $ F.openFile (toOsPath file) WriteMode
|
||||||
void $ tryIO $ modifyFileMode file $ removeModes otherGroupModes
|
void $ tryIO $ modifyFileMode file $ removeModes otherGroupModes
|
||||||
return h
|
return h
|
||||||
cleanup = hClose
|
cleanup = hClose
|
||||||
|
|
|
@ -18,6 +18,8 @@ module Utility.FileSize (
|
||||||
import Control.Exception (bracket)
|
import Control.Exception (bracket)
|
||||||
import System.IO
|
import System.IO
|
||||||
import Utility.FileSystemEncoding
|
import Utility.FileSystemEncoding
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
|
import Utility.OsPath
|
||||||
#else
|
#else
|
||||||
import System.PosixCompat.Files (fileSize)
|
import System.PosixCompat.Files (fileSize)
|
||||||
#endif
|
#endif
|
||||||
|
@ -36,7 +38,7 @@ getFileSize :: R.RawFilePath -> IO FileSize
|
||||||
#ifndef mingw32_HOST_OS
|
#ifndef mingw32_HOST_OS
|
||||||
getFileSize f = fmap (fromIntegral . fileSize) (R.getFileStatus f)
|
getFileSize f = fmap (fromIntegral . fileSize) (R.getFileStatus f)
|
||||||
#else
|
#else
|
||||||
getFileSize f = bracket (openFile (fromRawFilePath f) ReadMode) hClose hFileSize
|
getFileSize f = bracket (F.openFile (toOsPath f) ReadMode) hClose hFileSize
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{- Gets the size of the file, when its FileStatus is already known.
|
{- Gets the size of the file, when its FileStatus is already known.
|
||||||
|
|
|
@ -13,6 +13,9 @@ module Utility.HtmlDetect (
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Author
|
import Author
|
||||||
|
import qualified Utility.FileIO as F
|
||||||
|
import Utility.RawFilePath
|
||||||
|
import Utility.OsPath
|
||||||
|
|
||||||
import Text.HTML.TagSoup
|
import Text.HTML.TagSoup
|
||||||
import System.IO
|
import System.IO
|
||||||
|
@ -57,8 +60,8 @@ isHtmlBs = isHtml . B8.unpack
|
||||||
-- It would be equivalent to use isHtml <$> readFile file,
|
-- It would be equivalent to use isHtml <$> readFile file,
|
||||||
-- but since that would not read all of the file, the handle
|
-- but since that would not read all of the file, the handle
|
||||||
-- would remain open until it got garbage collected sometime later.
|
-- would remain open until it got garbage collected sometime later.
|
||||||
isHtmlFile :: FilePath -> IO Bool
|
isHtmlFile :: RawFilePath -> IO Bool
|
||||||
isHtmlFile file = withFile file ReadMode $ \h ->
|
isHtmlFile file = F.withFile (toOsPath file) ReadMode $ \h ->
|
||||||
isHtmlBs <$> B.hGet h htmlPrefixLength
|
isHtmlBs <$> B.hGet h htmlPrefixLength
|
||||||
|
|
||||||
-- | How much of the beginning of a html document is needed to detect it.
|
-- | How much of the beginning of a html document is needed to detect it.
|
||||||
|
|
|
@ -11,10 +11,9 @@
|
||||||
|
|
||||||
module Utility.OsPath where
|
module Utility.OsPath where
|
||||||
|
|
||||||
|
import Utility.FileSystemEncoding
|
||||||
|
|
||||||
#ifdef WITH_OSPATH
|
#ifdef WITH_OSPATH
|
||||||
|
|
||||||
import Utility.RawFilePath
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -36,4 +35,15 @@ fromOsPath = S.fromShort . getWindowsString . getOsString
|
||||||
fromOsPath = S.fromShort . getPosixString . getOsString
|
fromOsPath = S.fromShort . getPosixString . getOsString
|
||||||
#endif
|
#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
|
||||||
|
|
|
@ -14,11 +14,10 @@ status.
|
||||||
ghc-9.6.1 and above. Will need to switch from filepath-bytestring to
|
ghc-9.6.1 and above. Will need to switch from filepath-bytestring to
|
||||||
this, and to avoid a lot of ifdefs, probably only after git-annex no
|
this, and to avoid a lot of ifdefs, probably only after git-annex no
|
||||||
longers supports building with older ghc versions.
|
longers supports building with older ghc versions.
|
||||||
* withFile remains to be converted, and is used in several important code
|
* Utility.FileIO is used for most withFile and openFile, but not yet for
|
||||||
paths, including Annex.Journal and Annex.Link.
|
readFile, writeFile, and appendFile. Including versions of those from
|
||||||
There is a OSPath version in file-io library, but that is
|
bytestring.
|
||||||
not currently a git-annex dependency. (withFile is in base, and base is
|
* readFileStrict should be replaced with Utility.FileIO.readFile'
|
||||||
unlikely to convert to AFPP soon)
|
|
||||||
|
|
||||||
[[!tag confirmed]]
|
[[!tag confirmed]]
|
||||||
|
|
||||||
|
|
|
@ -336,7 +336,8 @@ Executable git-annex
|
||||||
Build-Depends:
|
Build-Depends:
|
||||||
os-string (>= 2.0.0),
|
os-string (>= 2.0.0),
|
||||||
directory (>= 1.3.8.3),
|
directory (>= 1.3.8.3),
|
||||||
filepath (>= 1.5.2.0)
|
filepath (>= 1.5.2.0),
|
||||||
|
file-io (>= 0.1.3)
|
||||||
CPP-Options: -DWITH_OSPATH
|
CPP-Options: -DWITH_OSPATH
|
||||||
|
|
||||||
if (os(windows))
|
if (os(windows))
|
||||||
|
@ -1134,6 +1135,7 @@ Executable git-annex
|
||||||
Utility.STM
|
Utility.STM
|
||||||
Utility.Su
|
Utility.Su
|
||||||
Utility.SystemDirectory
|
Utility.SystemDirectory
|
||||||
|
Utility.FileIO
|
||||||
Utility.Terminal
|
Utility.Terminal
|
||||||
Utility.TimeStamp
|
Utility.TimeStamp
|
||||||
Utility.TList
|
Utility.TList
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue