more OsPath conversion

Git.Types now uses it, as does TopFilePath, making for plenty of new
compile errors needing fixing.

Sponsored-by: Brock Spratlen
This commit is contained in:
Joey Hess 2025-01-23 16:15:00 -04:00
parent 12660314f1
commit ea775baccd
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
22 changed files with 159 additions and 163 deletions

View file

@ -34,8 +34,10 @@ initMagicMime = catchMaybeIO $ do
m <- magicOpen [MagicMime] m <- magicOpen [MagicMime]
liftIO $ getEnv "GIT_ANNEX_DIR" >>= \case liftIO $ getEnv "GIT_ANNEX_DIR" >>= \case
Nothing -> magicLoadDefault m Nothing -> magicLoadDefault m
Just d -> magicLoad m Just d -> magicLoad m $ fromOsPath $
(d </> "magic" </> "magic.mgc") toOsPath d
</> literalOsPath "magic"
</> literalOsPath "magic.mgc"
return m return m
#else #else
initMagicMime = return Nothing initMagicMime = return Nothing

View file

@ -10,6 +10,7 @@
module Assistant.Install.AutoStart where module Assistant.Install.AutoStart where
import Common
import Utility.FreeDesktop import Utility.FreeDesktop
#ifdef darwin_HOST_OS #ifdef darwin_HOST_OS
import Utility.OSX import Utility.OSX
@ -18,11 +19,11 @@ import Utility.SystemDirectory
import Utility.FileSystemEncoding import Utility.FileSystemEncoding
#endif #endif
installAutoStart :: FilePath -> FilePath -> IO () installAutoStart :: String -> OsPath -> IO ()
installAutoStart command file = do installAutoStart command file = do
#ifdef darwin_HOST_OS #ifdef darwin_HOST_OS
createDirectoryIfMissing True (fromRawFilePath (parentDir (toRawFilePath file))) createDirectoryIfMissing True (parentDir file)
writeFile file $ genOSXAutoStartFile osxAutoStartLabel command writeFile (fromOsPath file) $ genOSXAutoStartFile osxAutoStartLabel command
["assistant", "--autostart"] ["assistant", "--autostart"]
#else #else
writeDesktopMenuFile (fdoAutostart command) file writeDesktopMenuFile (fdoAutostart command) file

View file

@ -10,26 +10,24 @@
module Assistant.Install.Menu where module Assistant.Install.Menu where
import Common
import Utility.FreeDesktop import Utility.FreeDesktop
import Utility.FileSystemEncoding import Utility.FileSystemEncoding
import Utility.Path import Utility.Path
import System.IO import System.IO
import Utility.SystemDirectory import Utility.SystemDirectory
#ifndef darwin_HOST_OS
import System.FilePath
#endif
installMenu :: FilePath -> FilePath -> FilePath -> FilePath -> IO () installMenu :: String -> OsPath -> OsPath -> OsPath -> IO ()
#ifdef darwin_HOST_OS #ifdef darwin_HOST_OS
installMenu _command _menufile _iconsrcdir _icondir = return () installMenu _command _menufile _iconsrcdir _icondir = return ()
#else #else
installMenu command menufile iconsrcdir icondir = do installMenu command menufile iconsrcdir icondir = do
writeDesktopMenuFile (fdoDesktopMenu command) menufile writeDesktopMenuFile (fdoDesktopMenu command) menufile
installIcon (iconsrcdir </> "logo.svg") $ installIcon (iconsrcdir </> literalOsPath "logo.svg") $
iconFilePath (iconBaseName ++ ".svg") "scalable" icondir iconFilePath (toOsPath (iconBaseName ++ ".svg")) "scalable" icondir
installIcon (iconsrcdir </> "logo_16x16.png") $ installIcon (iconsrcdir </> literalOsPath "logo_16x16.png") $
iconFilePath (iconBaseName ++ ".png") "16x16" icondir iconFilePath (toOsPath (iconBaseName ++ ".png")) "16x16" icondir
#endif #endif
{- The command can be either just "git-annex", or the full path to use {- The command can be either just "git-annex", or the full path to use
@ -43,11 +41,11 @@ fdoDesktopMenu command = genDesktopEntry
(Just iconBaseName) (Just iconBaseName)
["Network", "FileTransfer"] ["Network", "FileTransfer"]
installIcon :: FilePath -> FilePath -> IO () installIcon :: OsPath -> OsPath -> IO ()
installIcon src dest = do installIcon src dest = do
createDirectoryIfMissing True (fromRawFilePath (parentDir (toRawFilePath dest))) createDirectoryIfMissing True (parentDir dest)
withBinaryFile src ReadMode $ \hin -> withBinaryFile (fromOsPath src) ReadMode $ \hin ->
withBinaryFile dest WriteMode $ \hout -> withBinaryFile (fromOsPath dest) WriteMode $ \hout ->
hGetContents hin >>= hPutStr hout hGetContents hin >>= hPutStr hout
iconBaseName :: String iconBaseName :: String

View file

@ -11,12 +11,8 @@
module Build.DesktopFile where module Build.DesktopFile where
import Utility.Exception import Common
import Utility.FreeDesktop import Utility.FreeDesktop
import Utility.Path
import Utility.Monad
import Utility.SystemDirectory
import Utility.FileSystemEncoding
import Config.Files import Config.Files
import Utility.OSX import Utility.OSX
import Assistant.Install.AutoStart import Assistant.Install.AutoStart
@ -25,8 +21,6 @@ import Assistant.Install.Menu
import System.Environment import System.Environment
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS
import System.Posix.User import System.Posix.User
import Data.Maybe
import Control.Applicative
import Prelude import Prelude
#endif #endif
@ -42,10 +36,10 @@ systemwideInstall = isroot <||> (not <$> userdirset)
systemwideInstall = return False systemwideInstall = return False
#endif #endif
inDestDir :: FilePath -> IO FilePath inDestDir :: OsPath -> IO OsPath
inDestDir f = do inDestDir f = do
destdir <- catchDefaultIO "" (getEnv "DESTDIR") destdir <- catchDefaultIO "" (getEnv "DESTDIR")
return $ destdir ++ "/" ++ f return $ toOsPath destdir <> literalOsPath "/" <> f
writeFDODesktop :: FilePath -> IO () writeFDODesktop :: FilePath -> IO ()
writeFDODesktop command = do writeFDODesktop command = do
@ -54,7 +48,7 @@ writeFDODesktop command = do
datadir <- if systemwide then return systemDataDir else userDataDir datadir <- if systemwide then return systemDataDir else userDataDir
menufile <- inDestDir (desktopMenuFilePath "git-annex" datadir) menufile <- inDestDir (desktopMenuFilePath "git-annex" datadir)
icondir <- inDestDir (iconDir datadir) icondir <- inDestDir (iconDir datadir)
installMenu command menufile "doc" icondir installMenu command menufile (literalOsPath "doc") icondir
configdir <- if systemwide then return systemConfigDir else userConfigDir configdir <- if systemwide then return systemConfigDir else userConfigDir
installAutoStart command installAutoStart command
@ -78,8 +72,8 @@ install command = do
( return () ( return ()
, do , do
programfile <- inDestDir =<< programFile programfile <- inDestDir =<< programFile
createDirectoryIfMissing True (fromRawFilePath (parentDir (toRawFilePath programfile))) createDirectoryIfMissing True (parentDir programfile)
writeFile programfile command writeFile (fromOsPath programfile) command
) )
installUser :: FilePath -> IO () installUser :: FilePath -> IO ()

View file

@ -9,28 +9,27 @@
module Config.Files where module Config.Files where
import Common
import Utility.FreeDesktop import Utility.FreeDesktop
import Utility.Exception import Utility.Exception
import System.FilePath
{- ~/.config/git-annex/file -} {- ~/.config/git-annex/file -}
userConfigFile :: FilePath -> IO FilePath userConfigFile :: OsPath -> IO OsPath
userConfigFile file = do userConfigFile file = do
dir <- userConfigDir dir <- toOsPath <$> userConfigDir
return $ dir </> "git-annex" </> file return $ dir </> literalOsPath "git-annex" </> file
autoStartFile :: IO FilePath autoStartFile :: IO OsPath
autoStartFile = userConfigFile "autostart" autoStartFile = userConfigFile (literalOsPath "autostart")
{- The path to git-annex is written here; which is useful when something {- The path to git-annex is written here; which is useful when something
- has installed it to some awful non-PATH location. -} - has installed it to some awful non-PATH location. -}
programFile :: IO FilePath programFile :: IO OsPath
programFile = userConfigFile "program" programFile = userConfigFile (literalOsPath "program")
{- A .noannex file in a git repository prevents git-annex from {- A .noannex file in a git repository prevents git-annex from
- initializing that repository. The content of the file is returned. -} - initializing that repository. The content of the file is returned. -}
noAnnexFileContent :: Maybe FilePath -> IO (Maybe String) noAnnexFileContent :: Maybe OsPath -> IO (Maybe String)
noAnnexFileContent repoworktree = case repoworktree of noAnnexFileContent repoworktree = case repoworktree of
Nothing -> return Nothing Nothing -> return Nothing
Just wt -> catchMaybeIO (readFile (wt </> ".noannex")) Just wt -> catchMaybeIO (readFile (fromOsPath (wt </> literalOsPath ".noannex")))

View file

@ -14,38 +14,37 @@ import Config.Files
import Utility.Tmp import Utility.Tmp
{- Returns anything listed in the autostart file (which may not exist). -} {- Returns anything listed in the autostart file (which may not exist). -}
readAutoStartFile :: IO [FilePath] readAutoStartFile :: IO [OsPath]
readAutoStartFile = do readAutoStartFile = do
f <- autoStartFile f <- autoStartFile
filter valid . nub . map dropTrailingPathSeparator . lines filter valid . nub . map (dropTrailingPathSeparator . toOsPath) . lines
<$> catchDefaultIO "" (readFile f) <$> catchDefaultIO "" (readFile (fromOsPath f))
where where
-- Ignore any relative paths; some old buggy versions added eg "." -- Ignore any relative paths; some old buggy versions added eg "."
valid = isAbsolute valid = isAbsolute
modifyAutoStartFile :: ([FilePath] -> [FilePath]) -> IO () modifyAutoStartFile :: ([OsPath] -> [OsPath]) -> IO ()
modifyAutoStartFile func = do modifyAutoStartFile func = do
dirs <- readAutoStartFile dirs <- readAutoStartFile
let dirs' = nubBy equalFilePath $ func dirs let dirs' = nubBy equalFilePath $ func dirs
when (dirs' /= dirs) $ do when (dirs' /= dirs) $ do
f <- autoStartFile f <- autoStartFile
createDirectoryIfMissing True $ createDirectoryIfMissing True (parentDir f)
fromRawFilePath (parentDir (toRawFilePath f))
viaTmp (writeFile . fromRawFilePath . fromOsPath) viaTmp (writeFile . fromRawFilePath . fromOsPath)
(toOsPath (toRawFilePath f)) (toOsPath f)
(unlines dirs') (unlines (map fromOsPath dirs'))
{- Adds a directory to the autostart file. If the directory is already {- Adds a directory to the autostart file. If the directory is already
- present, it's moved to the top, so it will be used as the default - present, it's moved to the top, so it will be used as the default
- when opening the webapp. -} - when opening the webapp. -}
addAutoStartFile :: FilePath -> IO () addAutoStartFile :: OsPath -> IO ()
addAutoStartFile path = do addAutoStartFile path = do
path' <- fromRawFilePath <$> absPath (toRawFilePath path) path' <- absPath path
modifyAutoStartFile $ (:) path' modifyAutoStartFile $ (:) path'
{- Removes a directory from the autostart file. -} {- Removes a directory from the autostart file. -}
removeAutoStartFile :: FilePath -> IO () removeAutoStartFile :: OsPath -> IO ()
removeAutoStartFile path = do removeAutoStartFile path = do
path' <- fromRawFilePath <$> absPath (toRawFilePath path) path' <- absPath path
modifyAutoStartFile $ modifyAutoStartFile $
filter (not . equalFilePath path') filter (not . equalFilePath path')

9
Git.hs
View file

@ -86,7 +86,7 @@ repoWorkTree Repo { location = Local { worktree = Just d } } = Just d
repoWorkTree _ = Nothing repoWorkTree _ = Nothing
{- Path to a local repository's .git directory. -} {- Path to a local repository's .git directory. -}
localGitDir :: Repo -> RawFilePath localGitDir :: Repo -> OsPath
localGitDir Repo { location = Local { gitdir = d } } = d localGitDir Repo { location = Local { gitdir = d } } = d
localGitDir _ = giveup "unknown localGitDir" localGitDir _ = giveup "unknown localGitDir"
@ -147,16 +147,17 @@ attributesLocal repo = localGitDir repo P.</> "info" P.</> "attributes"
{- Path to a given hook script in a repository, only if the hook exists {- Path to a given hook script in a repository, only if the hook exists
- and is executable. -} - and is executable. -}
hookPath :: String -> Repo -> IO (Maybe FilePath) hookPath :: String -> Repo -> IO (Maybe OsPath)
hookPath script repo = do hookPath script repo = do
let hook = fromRawFilePath (localGitDir repo) </> "hooks" </> script let hook = localGitDir repo </> literalOsPath "hooks" </> toOsPath script
ifM (catchBoolIO $ isexecutable hook) ifM (catchBoolIO $ isexecutable hook)
( return $ Just hook , return Nothing ) ( return $ Just hook , return Nothing )
where where
#if mingw32_HOST_OS #if mingw32_HOST_OS
isexecutable f = doesFileExist f isexecutable f = doesFileExist f
#else #else
isexecutable f = isExecutable . fileMode <$> getSymbolicLinkStatus f isexecutable f = isExecutable . fileMode
<$> getSymbolicLinkStatus (fromOsPath f)
#endif #endif
{- Makes the path to a local Repo be relative to the cwd. -} {- Makes the path to a local Repo be relative to the cwd. -}

View file

@ -99,7 +99,7 @@ read' repo = go repo
global :: IO (Maybe Repo) global :: IO (Maybe Repo)
global = do global = do
home <- myHomeDir home <- myHomeDir
ifM (doesFileExist $ home </> ".gitconfig") ifM (doesFileExist $ toOsPath home </> literalOsPath ".gitconfig")
( Just <$> withCreateProcess p go ( Just <$> withCreateProcess p go
, return Nothing , return Nothing
) )
@ -153,22 +153,22 @@ store' k v repo = repo
-} -}
updateLocation :: Repo -> IO Repo updateLocation :: Repo -> IO Repo
updateLocation r@(Repo { location = LocalUnknown d }) = case isBare r of updateLocation r@(Repo { location = LocalUnknown d }) = case isBare r of
Just True -> ifM (doesDirectoryExist (fromRawFilePath dotgit)) Just True -> ifM (doesDirectoryExist dotgit)
( updateLocation' r $ Local dotgit Nothing ( updateLocation' r $ Local dotgit Nothing
, updateLocation' r $ Local d Nothing , updateLocation' r $ Local d Nothing
) )
Just False -> mknonbare Just False -> mknonbare
{- core.bare not in config, probably because safe.directory {- core.bare not in config, probably because safe.directory
- did not allow reading the config -} - did not allow reading the config -}
Nothing -> ifM (Git.Construct.isBareRepo (fromRawFilePath d)) Nothing -> ifM (Git.Construct.isBareRepo d)
( mkbare ( mkbare
, mknonbare , mknonbare
) )
where where
dotgit = d P.</> ".git" dotgit = d </> literalOsPath ".git"
-- git treats eg ~/foo as a bare git repository located in -- git treats eg ~/foo as a bare git repository located in
-- ~/foo/.git if ~/foo/.git/config has core.bare=true -- ~/foo/.git if ~/foo/.git/config has core.bare=true
mkbare = ifM (doesDirectoryExist (fromRawFilePath dotgit)) mkbare = ifM (doesDirectoryExist dotgit)
( updateLocation' r $ Local dotgit Nothing ( updateLocation' r $ Local dotgit Nothing
, updateLocation' r $ Local d Nothing , updateLocation' r $ Local d Nothing
) )

View file

@ -176,43 +176,43 @@ fromRemoteLocation s knownurl repo = gen $ parseRemoteLocation s knownurl repo
fromRemotePath :: FilePath -> Repo -> IO Repo fromRemotePath :: FilePath -> Repo -> IO Repo
fromRemotePath dir repo = do fromRemotePath dir repo = do
dir' <- expandTilde dir dir' <- expandTilde dir
fromPath $ repoPath repo P.</> toRawFilePath dir' fromPath $ repoPath repo P.</> dir'
{- Git remotes can have a directory that is specified relative {- Git remotes can have a directory that is specified relative
- to the user's home directory, or that contains tilde expansions. - to the user's home directory, or that contains tilde expansions.
- This converts such a directory to an absolute path. - This converts such a directory to an absolute path.
- Note that it has to run on the system where the remote is. - Note that it has to run on the system where the remote is.
-} -}
repoAbsPath :: RawFilePath -> IO RawFilePath repoAbsPath :: OsPath -> IO OsPath
repoAbsPath d = do repoAbsPath d = do
d' <- expandTilde (fromRawFilePath d) d' <- expandTilde (fromOsPath d)
h <- myHomeDir h <- myHomeDir
return $ toRawFilePath $ h </> d' return $ toOsPath h </> d'
expandTilde :: FilePath -> IO FilePath expandTilde :: FilePath -> IO OsPath
#ifdef mingw32_HOST_OS #ifdef mingw32_HOST_OS
expandTilde = return expandTilde = return . toOsPath
#else #else
expandTilde p = expandt True p expandTilde p = expandt True p
-- If unable to expand a tilde, eg due to a user not existing, -- If unable to expand a tilde, eg due to a user not existing,
-- use the path as given. -- use the path as given.
`catchNonAsync` (const (return p)) `catchNonAsync` (const (return (toOsPath p)))
where where
expandt _ [] = return "" expandt _ [] = return $ literalOsPath ""
expandt _ ('/':cs) = do expandt _ ('/':cs) = do
v <- expandt True cs v <- expandt True cs
return ('/':v) return $ literalOsPath "/" <> v
expandt True ('~':'/':cs) = do expandt True ('~':'/':cs) = do
h <- myHomeDir h <- myHomeDir
return $ h </> cs return $ toOsPath h </> toOsPath cs
expandt True "~" = myHomeDir expandt True "~" = toOsPath <$> myHomeDir
expandt True ('~':cs) = do expandt True ('~':cs) = do
let (name, rest) = findname "" cs let (name, rest) = findname "" cs
u <- getUserEntryForName name u <- getUserEntryForName name
return $ homeDirectory u </> rest return $ toOsPath (homeDirectory u) </> toOsPath rest
expandt _ (c:cs) = do expandt _ (c:cs) = do
v <- expandt False cs v <- expandt False cs
return (c:v) return $ toOsPath [c] <> v
findname n [] = (n, "") findname n [] = (n, "")
findname n (c:cs) findname n (c:cs)
| c == '/' = (n, cs) | c == '/' = (n, cs)
@ -221,11 +221,11 @@ expandTilde p = expandt True p
{- Checks if a git repository exists in a directory. Does not find {- Checks if a git repository exists in a directory. Does not find
- git repositories in parent directories. -} - git repositories in parent directories. -}
checkForRepo :: RawFilePath -> IO (Maybe RepoLocation) checkForRepo :: OsPath -> IO (Maybe RepoLocation)
checkForRepo dir = checkForRepo dir =
check isRepo $ check isRepo $
check (checkGitDirFile dir) $ check (checkGitDirFile dir) $
check (checkdir (isBareRepo dir')) $ check (checkdir (isBareRepo dir)) $
return Nothing return Nothing
where where
check test cont = maybe cont (return . Just) =<< test check test cont = maybe cont (return . Just) =<< test
@ -234,23 +234,22 @@ checkForRepo dir =
, return Nothing , return Nothing
) )
isRepo = checkdir $ isRepo = checkdir $
doesFileExist (dir' </> ".git" </> "config") doesFileExist (dir </> literalOsPath ".git" </> literalOsPath "config")
<||> <||>
-- A git-worktree lacks .git/config, but has .git/gitdir. -- A git-worktree lacks .git/config, but has .git/gitdir.
-- (Normally the .git is a file, not a symlink, but it can -- (Normally the .git is a file, not a symlink, but it can
-- be converted to a symlink and git will still work; -- be converted to a symlink and git will still work;
-- this handles that case.) -- this handles that case.)
doesFileExist (dir' </> ".git" </> "gitdir") doesFileExist (dir </> literalOsPath ".git" </> literalOsPath "gitdir")
dir' = fromRawFilePath dir
isBareRepo :: FilePath -> IO Bool isBareRepo :: OsPath -> IO Bool
isBareRepo dir = doesFileExist (dir </> "config") isBareRepo dir = doesFileExist (dir </> literalOsPath "config")
<&&> doesDirectoryExist (dir </> "objects") <&&> doesDirectoryExist (dir </> literalOsPath "objects")
-- Check for a .git file. -- Check for a .git file.
checkGitDirFile :: RawFilePath -> IO (Maybe RepoLocation) checkGitDirFile :: OsPath -> IO (Maybe RepoLocation)
checkGitDirFile dir = adjustGitDirFile' $ Local checkGitDirFile dir = adjustGitDirFile' $ Local
{ gitdir = dir P.</> ".git" { gitdir = dir </> literalOsPath ".git"
, worktree = Just dir , worktree = Just dir
} }

View file

@ -51,7 +51,7 @@ get = do
Just d -> do Just d -> do
curr <- R.getCurrentDirectory curr <- R.getCurrentDirectory
unless (d `dirContains` curr) $ unless (d `dirContains` curr) $
setCurrentDirectory (fromRawFilePath d) setCurrentDirectory d
relPath $ addworktree wt r relPath $ addworktree wt r
where where
getpathenv s = do getpathenv s = do

View file

@ -32,13 +32,11 @@ import Common
import Git import Git
import Git.Quote import Git.Quote
import qualified System.FilePath.ByteString as P
import qualified System.FilePath.Posix.ByteString
import GHC.Generics import GHC.Generics
import Control.DeepSeq import Control.DeepSeq
{- A RawFilePath, relative to the top of the git repository. -} {- A path relative to the top of the git repository. -}
newtype TopFilePath = TopFilePath { getTopFilePath :: RawFilePath } newtype TopFilePath = TopFilePath { getTopFilePath :: OsPath }
deriving (Show, Eq, Ord, Generic) deriving (Show, Eq, Ord, Generic)
instance NFData TopFilePath instance NFData TopFilePath
@ -53,16 +51,16 @@ descBranchFilePath (BranchFilePath b f) =
UnquotedByteString (fromRef' b) <> ":" <> QuotedPath (getTopFilePath f) UnquotedByteString (fromRef' b) <> ":" <> QuotedPath (getTopFilePath f)
{- Path to a TopFilePath, within the provided git repo. -} {- Path to a TopFilePath, within the provided git repo. -}
fromTopFilePath :: TopFilePath -> Git.Repo -> RawFilePath fromTopFilePath :: TopFilePath -> Git.Repo -> OsPath
fromTopFilePath p repo = P.combine (repoPath repo) (getTopFilePath p) fromTopFilePath p repo = combine (repoPath repo) (getTopFilePath p)
{- The input FilePath can be absolute, or relative to the CWD. -} {- The input FilePath can be absolute, or relative to the CWD. -}
toTopFilePath :: RawFilePath -> Git.Repo -> IO TopFilePath toTopFilePath :: OsPath -> Git.Repo -> IO TopFilePath
toTopFilePath file repo = TopFilePath <$> relPathDirToFile (repoPath repo) file toTopFilePath file repo = TopFilePath <$> relPathDirToFile (repoPath repo) file
{- The input RawFilePath must already be relative to the top of the git {- The input RawFilePath must already be relative to the top of the git
- repository -} - repository -}
asTopFilePath :: RawFilePath -> TopFilePath asTopFilePath :: OsPath -> TopFilePath
asTopFilePath file = TopFilePath file asTopFilePath file = TopFilePath file
{- Git may use a different representation of a path when storing {- Git may use a different representation of a path when storing
@ -72,25 +70,24 @@ asTopFilePath file = TopFilePath file
- despite Windows using '\'. - despite Windows using '\'.
- -
-} -}
type InternalGitPath = RawFilePath type InternalGitPath = OsPath
toInternalGitPath :: RawFilePath -> InternalGitPath toInternalGitPath :: OsPath -> InternalGitPath
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS
toInternalGitPath = id toInternalGitPath = id
#else #else
toInternalGitPath = encodeBS . replace "\\" "/" . decodeBS toInternalGitPath = toOsPath . encodeBS . replace "\\" "/" . decodeBS . fromOsPath
#endif #endif
fromInternalGitPath :: InternalGitPath -> RawFilePath fromInternalGitPath :: InternalGitPath -> OsPath
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS
fromInternalGitPath = id fromInternalGitPath = id
#else #else
fromInternalGitPath = encodeBS . replace "/" "\\" . decodeBS fromInternalGitPath = toOsPath . encodeBS . replace "/" "\\" . decodeBS . fromOsPath
#endif #endif
{- isAbsolute on Windows does not think "/foo" or "\foo" is absolute, {- isAbsolute on Windows does not think "/foo" or "\foo" is absolute,
- so try posix paths. - so try posix paths.
-} -}
absoluteGitPath :: RawFilePath -> Bool absoluteGitPath :: RawFilePath -> Bool
absoluteGitPath p = P.isAbsolute p || absoluteGitPath p = isAbsolute p || isAbsolute (toInternalGitPath p)
System.FilePath.Posix.ByteString.isAbsolute (toInternalGitPath p)

View file

@ -83,7 +83,7 @@ instance HashableBlob Builder where
{- Injects a blob into git. Unfortunately, the current git-hash-object {- Injects a blob into git. Unfortunately, the current git-hash-object
- interface does not allow batch hashing without using temp files. -} - interface does not allow batch hashing without using temp files. -}
hashBlob :: HashableBlob b => HashObjectHandle -> b -> IO Sha hashBlob :: HashableBlob b => HashObjectHandle -> b -> IO Sha
hashBlob h b = withTmpFile (toOsPath "hash") $ \tmp tmph -> do hashBlob h b = withTmpFile (literalOsPath "hash") $ \tmp tmph -> do
hashableBlobToHandle tmph b hashableBlobToHandle tmph b
hClose tmph hClose tmph
hashFile h (fromOsPath tmp) hashFile h (fromOsPath tmp)

View file

@ -50,7 +50,7 @@ hookFile h r = localGitDir r P.</> "hooks" P.</> hookName h
- is run with a bundled bash, so should start with #!/bin/sh - is run with a bundled bash, so should start with #!/bin/sh
-} -}
hookWrite :: Hook -> Repo -> IO Bool hookWrite :: Hook -> Repo -> IO Bool
hookWrite h r = ifM (doesFileExist (fromRawFilePath f)) hookWrite h r = ifM (doesFileExist f)
( expectedContent h r >>= \case ( expectedContent h r >>= \case
UnexpectedContent -> return False UnexpectedContent -> return False
ExpectedContent -> return True ExpectedContent -> return True
@ -81,7 +81,7 @@ hookUnWrite h r = ifM (doesFileExist f)
, return True , return True
) )
where where
f = fromRawFilePath $ hookFile h r f = hookFile h r
data ExpectedContent = UnexpectedContent | ExpectedContent | OldExpectedContent data ExpectedContent = UnexpectedContent | ExpectedContent | OldExpectedContent

View file

@ -113,8 +113,8 @@ exists ref = runBool
{- The file used to record a ref. (Git also stores some refs in a {- The file used to record a ref. (Git also stores some refs in a
- packed-refs file.) -} - packed-refs file.) -}
file :: Ref -> Repo -> FilePath file :: Ref -> Repo -> OsPath
file ref repo = fromRawFilePath (localGitDir repo) </> fromRef ref file ref repo = localGitDir repo </> toOsPath (fromRef' ref)
{- Checks if HEAD exists. It generally will, except for in a repository {- Checks if HEAD exists. It generally will, except for in a repository
- that was just created. -} - that was just created. -}

View file

@ -137,7 +137,7 @@ mkTreeOutput fm ot s f = concat
, " " , " "
, fromRef s , fromRef s
, "\t" , "\t"
, takeFileName (fromRawFilePath (getTopFilePath f)) , fromOsPath (takeFileName (getTopFilePath f))
, "\NUL" , "\NUL"
] ]

View file

@ -9,6 +9,10 @@
module Git.Types where module Git.Types where
import Utility.SafeCommand
import Utility.FileSystemEncoding
import Utility.OsPath
import Network.URI import Network.URI
import Data.String import Data.String
import Data.Default import Data.Default
@ -16,8 +20,6 @@ import qualified Data.Map as M
import qualified Data.ByteString as S import qualified Data.ByteString as S
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
import System.Posix.Types import System.Posix.Types
import Utility.SafeCommand
import Utility.FileSystemEncoding
import qualified Data.Semigroup as Sem import qualified Data.Semigroup as Sem
import Prelude import Prelude
@ -32,8 +34,8 @@ import Prelude
- else known about it. - else known about it.
-} -}
data RepoLocation data RepoLocation
= Local { gitdir :: RawFilePath, worktree :: Maybe RawFilePath } = Local { gitdir :: OsPath, worktree :: Maybe OsPath }
| LocalUnknown RawFilePath | LocalUnknown OsPath
| Url URI | Url URI
| UnparseableUrl String | UnparseableUrl String
| Unknown | Unknown

View file

@ -28,13 +28,12 @@ module Utility.FreeDesktop (
userDesktopDir userDesktopDir
) where ) where
import Common
import Utility.Exception import Utility.Exception
import Utility.UserInfo import Utility.UserInfo
import Utility.Process import Utility.Process
import System.Environment import System.Environment
import System.FilePath
import System.Directory
import Data.List import Data.List
import Data.Maybe import Data.Maybe
import Control.Applicative import Control.Applicative
@ -78,53 +77,53 @@ buildDesktopMenuFile d = unlines ("[Desktop Entry]" : map keyvalue d) ++ "\n"
where where
keyvalue (k, v) = k ++ "=" ++ toString v keyvalue (k, v) = k ++ "=" ++ toString v
writeDesktopMenuFile :: DesktopEntry -> String -> IO () writeDesktopMenuFile :: DesktopEntry -> OsPath -> IO ()
writeDesktopMenuFile d file = do writeDesktopMenuFile d file = do
createDirectoryIfMissing True (takeDirectory file) createDirectoryIfMissing True (takeDirectory file)
writeFile file $ buildDesktopMenuFile d writeFile (fromOsPath file) $ buildDesktopMenuFile d
{- Path to use for a desktop menu file, in either the systemDataDir or {- Path to use for a desktop menu file, in either the systemDataDir or
- the userDataDir -} - the userDataDir -}
desktopMenuFilePath :: String -> FilePath -> FilePath desktopMenuFilePath :: String -> OsPath -> OsPath
desktopMenuFilePath basename datadir = desktopMenuFilePath basename datadir =
datadir </> "applications" </> desktopfile basename datadir </> literalOsPath "applications" </> desktopfile basename
{- Path to use for a desktop autostart file, in either the systemDataDir {- Path to use for a desktop autostart file, in either the systemDataDir
- or the userDataDir -} - or the userDataDir -}
autoStartPath :: String -> FilePath -> FilePath autoStartPath :: String -> OsPath -> OsPath
autoStartPath basename configdir = autoStartPath basename configdir =
configdir </> "autostart" </> desktopfile basename configdir </> literalOsPath "autostart" </> desktopfile basename
{- Base directory to install an icon file, in either the systemDataDir {- Base directory to install an icon file, in either the systemDataDir
- or the userDatadir. -} - or the userDatadir. -}
iconDir :: FilePath -> FilePath iconDir :: OsPath -> OsPath
iconDir datadir = datadir </> "icons" </> "hicolor" iconDir datadir = datadir </> literalOsPath "icons" </> literalOsPath "hicolor"
{- Filename of an icon, given the iconDir to use. {- Filename of an icon, given the iconDir to use.
- -
- The resolution is something like "48x48" or "scalable". -} - The resolution is something like "48x48" or "scalable". -}
iconFilePath :: FilePath -> String -> FilePath -> FilePath iconFilePath :: OsPath -> String -> OsPath -> OsPath
iconFilePath file resolution icondir = iconFilePath file resolution icondir =
icondir </> resolution </> "apps" </> file icondir </> toOsPath resolution </> literalOsPath "apps" </> file
desktopfile :: FilePath -> FilePath desktopfile :: FilePath -> OsPath
desktopfile f = f ++ ".desktop" desktopfile f = toOsPath $ f ++ ".desktop"
{- Directory used for installation of system wide data files.. -} {- Directory used for installation of system wide data files.. -}
systemDataDir :: FilePath systemDataDir :: OsPath
systemDataDir = "/usr/share" systemDataDir = literalOsPath "/usr/share"
{- Directory used for installation of system wide config files. -} {- Directory used for installation of system wide config files. -}
systemConfigDir :: FilePath systemConfigDir :: OsPath
systemConfigDir = "/etc/xdg" systemConfigDir = literalOsPath "/etc/xdg"
{- Directory for user data files. -} {- Directory for user data files. -}
userDataDir :: IO FilePath userDataDir :: IO OsPath
userDataDir = xdgEnvHome "DATA_HOME" ".local/share" userDataDir = toOsPath <$> xdgEnvHome "DATA_HOME" ".local/share"
{- Directory for user config files. -} {- Directory for user config files. -}
userConfigDir :: IO FilePath userConfigDir :: IO OsPath
userConfigDir = xdgEnvHome "CONFIG_HOME" ".config" userConfigDir = toOsPath <$> xdgEnvHome "CONFIG_HOME" ".config"
{- Directory for the user's Desktop, may be localized. {- Directory for the user's Desktop, may be localized.
- -
@ -142,6 +141,6 @@ userDesktopDir = maybe fallback return =<< (parse <$> xdg_user_dir)
xdgEnvHome :: String -> String -> IO String xdgEnvHome :: String -> String -> IO String
xdgEnvHome envbase homedef = do xdgEnvHome envbase homedef = do
home <- myHomeDir home <- toOsPath <$> myHomeDir
catchDefaultIO (home </> homedef) $ catchDefaultIO (fromOsPath $ home </> toOsPath homedef) $
getEnv $ "XDG_" ++ envbase getEnv ("XDG_" ++ envbase)

View file

@ -14,20 +14,19 @@ module Utility.OSX (
genOSXAutoStartFile, genOSXAutoStartFile,
) where ) where
import Common
import Utility.UserInfo import Utility.UserInfo
import System.FilePath autoStartBase :: String -> OsPath
autoStartBase label = literalOsPath "Library" </> literalOsPath "LaunchAgents" </> literalOsPath (label ++ ".plist")
autoStartBase :: String -> FilePath systemAutoStart :: String -> OsPath
autoStartBase label = "Library" </> "LaunchAgents" </> label ++ ".plist" systemAutoStart label = literalOsPath "/" </> autoStartBase label
systemAutoStart :: String -> FilePath userAutoStart :: String -> IO OsPath
systemAutoStart label = "/" </> autoStartBase label
userAutoStart :: String -> IO FilePath
userAutoStart label = do userAutoStart label = do
home <- myHomeDir home <- myHomeDir
return $ home </> autoStartBase label return $ toOsPath home </> autoStartBase label
{- Generates an OSX autostart plist file with a given label, command, and {- Generates an OSX autostart plist file with a given label, command, and
- params to run at boot or login. -} - params to run at boot or login. -}

View file

@ -21,11 +21,12 @@ import System.OsString as X hiding (length)
import qualified System.OsString import qualified System.OsString
import qualified Data.ByteString as B import qualified Data.ByteString as B
import Utility.OsPath import Utility.OsPath
import Prelude ((.), Int)
{- Avoid System.OsString.length, which returns the number of code points on {- Avoid System.OsString.length, which returns the number of code points on
- windows. This is the number of bytes. -} - windows. This is the number of bytes. -}
length :: System.OsString.OsString -> Int length :: System.OsString.OsString -> Int
length = B.length . fromOsString length = B.length . fromOsPath
#else #else
import Data.ByteString as X hiding (length) import Data.ByteString as X hiding (length)
import Data.ByteString (length) import Data.ByteString (length)

View file

@ -28,7 +28,6 @@ module Utility.Path (
) where ) where
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified System.FilePath.ByteString as PB
import Data.List import Data.List
import Data.Maybe import Data.Maybe
import Control.Monad import Control.Monad
@ -70,9 +69,10 @@ simplifyPath path = dropTrailingPathSeparator $
norm c [] = reverse c norm c [] = reverse c
norm c (p:ps) norm c (p:ps)
| p' == ".." && not (null c) && dropTrailingPathSeparator (c !! 0) /= ".." = | p' == dotdot && not (null c)
norm (drop 1 c) ps && dropTrailingPathSeparator (c !! 0) /= dotdot =
| p' == "." = norm c ps norm (drop 1 c) ps
| p' == dot = norm c ps
| otherwise = norm (p:c) ps | otherwise = norm (p:c) ps
where where
p' = dropTrailingPathSeparator p p' = dropTrailingPathSeparator p
@ -86,8 +86,8 @@ parentDir = takeDirectory . dropTrailingPathSeparator
upFrom :: OsPath -> Maybe OsPath upFrom :: OsPath -> Maybe OsPath
upFrom dir upFrom dir
| length dirs < 2 = Nothing | length dirs < 2 = Nothing
| otherwise = Just $ joinDrive drive $ toOsPath $ | otherwise = Just $ joinDrive drive $
B.intercalate (B.singleton PB.pathSeparator) $ init dirs OS.intercalate (OS.singleton pathSeparator) $ init dirs
where where
-- on Unix, the drive will be "/" when the dir is absolute, -- on Unix, the drive will be "/" when the dir is absolute,
-- otherwise "" -- otherwise ""
@ -101,8 +101,8 @@ upFrom dir
dirContains :: OsPath -> OsPath -> Bool dirContains :: OsPath -> OsPath -> Bool
dirContains a b = a == b dirContains a b = a == b
|| a' == b' || a' == b'
|| (a'' `B.isPrefixOf` b' && avoiddotdotb) || (a'' `OS.isPrefixOf` b' && avoiddotdotb)
|| a' == "." && normalise ("." </> b') == b' && nodotdot b' || a' == dot && normalise (dot </> b') == b' && nodotdot b'
|| dotdotcontains || dotdotcontains
where where
a' = norm a a' = norm a
@ -124,7 +124,7 @@ dirContains a b = a == b
nodotdot p = all (not . isdotdot) (splitPath p) nodotdot p = all (not . isdotdot) (splitPath p)
isdotdot s = dropTrailingPathSeparator s == ".." isdotdot s = dropTrailingPathSeparator s == dotdot
{- This handles the case where a is ".." or "../.." etc, {- This handles the case where a is ".." or "../.." etc,
- and b is "foo" or "../foo" etc. The rule is that when - and b is "foo" or "../foo" etc. The rule is that when
@ -185,10 +185,10 @@ runSegmentPaths' si c a paths = segmentPaths' si c paths <$> a paths
- count as dotfiles. -} - count as dotfiles. -}
dotfile :: OsPath -> Bool dotfile :: OsPath -> Bool
dotfile file dotfile file
| f == "." = False | f == dot = False
| f == ".." = False | f == dotdot = False
| f == "" = False | f == literalOsPath "" = False
| otherwise = "." `OS.isPrefixOf` f || dotfile (takeDirectory file) | otherwise = dot `OS.isPrefixOf` f || dotfile (takeDirectory file)
where where
f = takeFileName file f = takeFileName file
@ -226,7 +226,7 @@ relPathDirToFileAbs from to
common = map fst $ takeWhile same $ zip pfrom pto common = map fst $ takeWhile same $ zip pfrom pto
same (c,d) = c == d same (c,d) = c == d
uncommon = drop numcommon pto uncommon = drop numcommon pto
dotdots = replicate (length pfrom - numcommon) ".." dotdots = replicate (length pfrom - numcommon) dotdot
numcommon = length common numcommon = length common
#ifdef mingw32_HOST_OS #ifdef mingw32_HOST_OS
normdrive = map toLower normdrive = map toLower
@ -255,7 +255,7 @@ inSearchPath command = isJust <$> searchPath command
searchPath :: String -> IO (Maybe OsPath) searchPath :: String -> IO (Maybe OsPath)
searchPath command searchPath command
| isAbsolute command' = copyright $ check command' | isAbsolute command' = copyright $ check command'
| otherwise = getSearchPath >>= getM indir . map toOsPath | otherwise = getSearchPath >>= getM indir
where where
command' = toOsPath command command' = toOsPath command
indir d = check (d </> command') indir d = check (d </> command')
@ -275,7 +275,14 @@ searchPath command
searchPathContents :: (OsPath -> Bool) -> IO [OsPath] searchPathContents :: (OsPath -> Bool) -> IO [OsPath]
searchPathContents p = searchPathContents p =
filterM doesFileExist filterM doesFileExist
=<< (concat <$> (getSearchPath >>= mapM (go . toOsPath))) =<< (concat <$> (getSearchPath >>= mapM go))
where where
go d = map (d </>) . filter p go d = map (d </>) . filter p
<$> catchDefaultIO [] (getDirectoryContents d) <$> catchDefaultIO [] (getDirectoryContents d)
dot :: OsPath
dot = literalOsPath "."
dotdot :: OsPath
dotdot = literalOsPath ".."

View file

@ -17,7 +17,6 @@ module Utility.Path.AbsRel (
relHome, relHome,
) where ) where
import System.FilePath.ByteString
import qualified Data.ByteString as B import qualified Data.ByteString as B
import Control.Applicative import Control.Applicative
import Prelude import Prelude

View file

@ -17,7 +17,6 @@ module Utility.Path.Tests (
prop_dirContains_regressionTest, prop_dirContains_regressionTest,
) where ) where
import System.FilePath.ByteString
import qualified Data.ByteString as B import qualified Data.ByteString as B
import Data.List import Data.List
import Data.Maybe import Data.Maybe
@ -25,8 +24,8 @@ import Data.Char
import Control.Applicative import Control.Applicative
import Prelude import Prelude
import Common
import Utility.Path import Utility.Path
import Utility.FileSystemEncoding
import Utility.QuickCheck import Utility.QuickCheck
prop_upFrom_basics :: TestableFilePath -> Bool prop_upFrom_basics :: TestableFilePath -> Bool