pathtype 0.6 → 0.7
raw patch · 15 files changed
+3181/−1839 lines, 15 filesdep +taggeddep +transformersdep +utility-ht
Dependencies added: tagged, transformers, utility-ht
Files
- pathtype.cabal +215/−85
- posix/System/Path/Host.hs +2/−0
- src/System/Path.hs +21/−85
- src/System/Path/Directory.hs +76/−56
- src/System/Path/Generic.hs +22/−0
- src/System/Path/IO.hs +29/−20
- src/System/Path/Internal.hs +1832/−1210
- src/System/Path/Posix.hs +194/−9
- src/System/Path/RegularExpression.hs +31/−0
- src/System/Path/Windows.hs +204/−9
- test/Test.hs +11/−2
- test/TestResult.hs +524/−351
- test/TestTemplate.hs +5/−3
- tool/CreateTest.hs +13/−9
- windows/System/Path/Host.hs +2/−0
pathtype.cabal view
@@ -1,87 +1,204 @@ Name: pathtype-Version: 0.6+Version: 0.7 Synopsis: Type-safe replacement for System.FilePath etc-Description: This package provides type-safe access to filepath manipulations.- .- "System.Path" is designed to be used instead of "System.FilePath".- (It is intended to provide versions of functions from that- module which have equivalent functionality but are more- typesafe). "System.Path.Directory" is a companion module- providing a type-safe alternative to "System.Directory".- .- The heart of this module is the @'Path' ar fd@ abstract type which- represents file and directory paths. The idea is that there are- two phantom type parameters - the first should be 'Abs' or 'Rel',- and the second 'File' or 'Dir'. A number of type synonyms are- provided for common types:- .- > type AbsFile = Path Abs File- > type RelFile = Path Rel File- > type AbsDir = Path Abs Dir- > type RelDir = Path Rel Dir- >- > type AbsPath fd = Path Abs fd- > type RelPath fd = Path Rel fd- > type FilePath ar = Path ar File- > type DirPath ar = Path ar Dir- .- The type of the 'combine' (aka '</>') function gives the idea:- .- > (</>) :: DirPath ar -> RelPath fd -> Path ar fd- .- Together this enables us to give more meaningful types to- a lot of the functions, and (hopefully) catch a bunch more- errors at compile time.- .- Overloaded string literals are supported, so with the @OverloadedStrings@- extension enabled, you can:- .- > f :: FilePath ar- > f = "tmp" </> "someFile" <.> "ext"- .- If you don't want to use @OverloadedStrings@, you can use the construction fns:- .- > f :: FilePath ar- > f = asDirPath "tmp" </> asFilePath "someFile" <.> "ext"- .- or...- .- > f :: FilePath ar- > f = asPath "tmp" </> asPath "someFile" <.> "ext"- .- or just...- .- > f :: FilePath ar- > f = asPath "tmp/someFile.ext"- .- One point to note is that whether one of these is interpreted as- an absolute or a relative path depends on the type at which it is- used:- .- > *System.Path> f :: AbsFile- > /tmp/someFile.ext- > *System.Path> f :: RelFile- > tmp/someFile.ext- .- You will typically want to import as follows:- .- > import Prelude hiding (FilePath)- > import System.Path- > import System.Path.Directory- > import System.Path.IO- .- The basic API (and properties satisfied) are heavily influenced- by Neil Mitchell's "System.FilePath" module.- .- Related packages:- .- * @path@: Provides a wrapper type around 'FilePath'- and maps to functions from @filepath@ package.- This warrants consistency with @filepath@ functions.- Requires Template Haskell.- .- * @data-filepath@:- Requires 'Typeable' and Template Haskell.+Description:+ This package provides type-safe access to filepath manipulations.+ .+ "System.Path" is designed to be used instead of "System.FilePath".+ (It is intended to provide versions of functions from that+ module which have equivalent functionality but are more+ typesafe). "System.Path.Directory" is a companion module+ providing a type-safe alternative to "System.Directory".+ .+ The heart of this module is the @'Path' ar fd@ abstract type which+ represents file and directory paths. The idea is that there are+ two type parameters - the first should be 'Abs' or 'Rel',+ and the second 'File' or 'Dir'. A number of type synonyms are+ provided for common types:+ .+ > type AbsFile = Path Abs File+ > type RelFile = Path Rel File+ > type AbsDir = Path Abs Dir+ > type RelDir = Path Rel Dir+ >+ > type AbsPath fd = Path Abs fd+ > type RelPath fd = Path Rel fd+ > type FilePath ar = Path ar File+ > type DirPath ar = Path ar Dir+ .+ The type of the 'combine' (aka '</>') function gives the idea:+ .+ > (</>) :: DirPath ar -> RelPath fd -> Path ar fd+ .+ Together this enables us to give more meaningful types to+ a lot of the functions, and (hopefully) catch a bunch more+ errors at compile time.+ .+ You can use the construction functions as follows:+ .+ > f :: Path.RelFile+ > f = relDir "tmp" </> relFile "someFile" <.> "ext"+ .+ or...+ .+ > f :: Path.RelFile+ > f = dirPath "tmp" </> filePath "someFile" <.> "ext"+ .+ or...+ .+ > f :: Path.RelFile+ > f = path "tmp" </> path "someFile" <.> "ext"+ .+ or just...+ .+ > f :: Path.RelFile+ > f = relFile "tmp/someFile.ext"+ .+ The first and the last implementations force the most specific types+ and thus should be prefered.+ .+ Overloaded string literals are no longer supported,+ since this extension is intended for alternative text storage types.+ It would also decrease the type safety+ if you could omit the path type and let the compiler guess its type.+ .+ You will typically want to import as follows:+ .+ > import qualified System.Path.Directory as Dir+ > import qualified System.Path.IO as PathIO+ > import qualified System.Path as Path+ > import System.Path ((</>))+ .+ "System.Path.Generic" provides all functions with the OS as type parameter.+ "System.Path.Posix" and "System.Path.Windows"+ offers only path constructors and destructors+ fixed to the corresponding operating system.+ "System.Path" exports either "System.Path.Posix" or "System.Path.Windows"+ depending on the host system+ and additionally the manipulation functions from "System.Path.Generic".+ This mix should be appropriate for the average use+ and should free the user from writing type annotations.+ .+ The basic API (and properties satisfied) are heavily influenced+ by Neil Mitchell's "System.FilePath" module.+ .+ .+ Some notes on how to choose proper type parameters:+ .+ The @ar@ and the @fd@ type parameters have quite different meaning.+ The types @Abs@ and @Rel@ refer to a property of the path,+ whereas the type @File@ and @Dir@ refers to a property of a disk object.+ You can decide whether a path is absolute or relative+ by just watching (the beginning of) the path string.+ In contrast to that, you have to access the disk+ in order to check the existence and type of an disk object.+ Even more, the disk object might change at any time,+ e.g. the user might delete a file and create a directory of the same name,+ or the disk object might not exist,+ and the purpose of the path is to create an according file or directory.+ That's why even if you have a path of type @FilePath ar@,+ every function accessing the file must check+ that the refered object exists and is a file.+ Conversely, there is not much sense in checking the disk object type+ and then chosing the path accordingly.+ Instead, you must choose the path type according+ to what type of disk object your application needs.+ The reality check must be performed+ and is performed by the standard functions+ for every access to the object.+ If an disk object is not of the type required by the path type+ then this is a runtime exception that must be handled at runtime+ but it is not a programming error.+ .+ Sometimes you have to change the type of a path+ as an intermediate step to construct a path for an object of different type.+ E.g. you may convert the path \"pkg\" from @DirPath@ to @FilePath@+ because in the next step you like to extend it to \"pkg.tar.gz\".+ This is valid use of the @Path@ type.+ E.g. the function @dropExtensions@+ reduces the @FilePath@ \"pkg.tar.gz\" to the new @FilePath@ \"pkg\"+ although no-one expects that there is or will be a file with name \"pkg\".+ Thus, if a function has a @FilePath@ parameter+ then there is no warranty that it accesses the according file+ and does not touch related disk objects.+ It may well be that the function derives other file and directory names+ from the path and accesses them.+ That is, a @FilePath@ or @DirPath@ parameter+ is mainly for documentation purposes+ but it cannot prevent you seriously from any damage.+ .+ How to cope with user input?+ You may get a path from the user, e.g. as command-line argument.+ It might be either absolute or relative+ and it might refer to an actual file or directory or+ to something yet non-existing.+ In most cases it will not be important+ whether the path is absolute or relative,+ thus you should choose the @AbsOrRel@ type parameter.+ If somewhere in the program an @Abs@ path is needed+ then you can assert that the path is actually absolutized somewhere+ e.g. by @dynamicMakeAbsolute@.+ If you prevent usage of @genericMakeAbsolute@+ then you avoid to absolutize a path that is already absolutized.+ .+ The choice of the @fd@ type parameter follows a different reasoning:+ Often you have a clear idea of+ whether the user must pass a file or directory path.+ The rule is: Just give the path the type you expect+ but do not perform any checking+ (unless you want to warn the user earlier about imminent danger).+ The disk object type must checked for every access to the object, anyway,+ so there is no point in checking it immediately.+ With your choice of the @fd@ parameter+ you just document its intended use.+ .+ It might be that the path is only a base name+ used to construct other directory and file names.+ E.g. for an Audacity project named @music@+ you have to create the directory @music_data@ and the file @music.aup@.+ In this case we recommend to give @music@ the type @FilePath@.+ This type warrants that there is at least one final path component+ in contrast to a directory path that might be empty.+ You can easily convert a file path to a directory path+ using @Path.dirFromFile@.+ The reverse conversion is partial.+ .+ .+ Some notes on file system links:+ .+ This package does not explicitly handle file system links.+ We treat a file path containing links like any other file path.+ The same holds for directory paths.+ A link is handled like any other path component.+ .+ .+ Some notes on drive-relative paths on Windows:+ .+ We use the @Rel@ type for paths that can be relative to any directory.+ We use the @Abs@ type for all other paths,+ i.e. for paths with explicit locations or+ with restrictions on the set of locations.+ Windows has a notion of drives and+ maintains a current directory for every drive.+ E.g. the path @\"c:text.txt\"@ refers to the current directory of drive @C@.+ Since it cannot be freely combined with other directories+ we treat this path like an absolute path.+ This is consistent with the behaviour of the @filepath@ package.+ E.g. @filepath@ evaluates all of the expressions+ @\"\\\\abs\" \<\/\> \"c:driverel\"@, @\"c:\\\\abs\" \<\/\> \"c:driverel\"@,+ @\"d:\\\\abs\" \<\/\> \"c:driverel\"@ to @\"c:driverel\"@.+ In our package you would have to use @genericMakeAbsolute@+ but we recommend to avoid its use.+ .+ Related packages:+ .+ * @path@: Provides a wrapper type around 'FilePath'+ and maps to functions from @filepath@ package.+ This warrants consistency with @filepath@ functions.+ Requires Template Haskell.+ .+ * @data-filepath@:+ Requires 'Typeable' and Template Haskell. Stability: experimental License: BSD3 Category: System@@ -93,7 +210,8 @@ Cabal-Version: >=1.8 Extra-Source-Files: test/TestTemplate.hs- src/System/Path/Internal.hs+ posix/System/Path/Host.hs+ windows/System/Path/Host.hs directory/pre-1.2/System/Path/ModificationTime.hs directory/post-incl-1.2/System/Path/ModificationTime.hs @@ -102,7 +220,7 @@ Location: http://hub.darcs.net/thielema/pathtype/ Source-Repository this- Tag: 0.6+ Tag: 0.7 Type: darcs Location: http://hub.darcs.net/thielema/pathtype/ @@ -116,9 +234,12 @@ Library Build-Depends:+ utility-ht >=0.0.11 && <0.1, QuickCheck >= 2.1.0.1 && < 3, deepseq >= 1.3 && <1.5, time >= 1.0 && < 2,+ transformers >=0.3 && <0.5,+ tagged >=0.7 && <0.9, base >= 4 && < 5 If flag(old-time)@@ -129,13 +250,21 @@ Hs-Source-Dirs: directory/post-incl-1.2 Hs-Source-Dirs: src+ If os(windows)+ Hs-Source-Dirs: windows+ Else+ Hs-Source-Dirs: posix Exposed-Modules: System.Path+ System.Path.Generic System.Path.Directory System.Path.IO System.Path.Posix System.Path.Windows Other-Modules:+ System.Path.Host+ System.Path.Internal+ System.Path.RegularExpression System.Path.ModificationTime GHC-Options: -Wall -fwarn-tabs -fwarn-incomplete-record-updates -fwarn-unused-do-bind@@ -156,9 +285,10 @@ Executable create-pathtype-test If flag(buildTools) Build-Depends:+ utility-ht >=0.0.12 && <0.1, base Else- Buildable: True+ Buildable: False Main-Is: CreateTest.hs Hs-Source-Dirs: tool
+ posix/System/Path/Host.hs view
@@ -0,0 +1,2 @@+module System.Path.Host (module System.Path.Posix) where+import System.Path.Posix
src/System/Path.hs view
@@ -1,86 +1,22 @@-{-# LANGUAGE CPP #-}--- | This module provides type-safe access to filepath manipulations.------ It is designed to be imported instead of "System.FilePath".--- (It is intended to provide versions of functions from that--- module which have equivalent functionality but are more--- typesafe). "System.Path.Directory" is a companion module--- providing a type-safe alternative to "System.Directory".------ The heart of this module is the @'Path' ar fd@ abstract type which--- represents file and directory paths. The idea is that there are--- two phantom type parameters - the first should be 'Abs' or 'Rel',--- and the second 'File' or 'Dir'. A number of type synonyms are--- provided for common types:------ > type AbsFile = Path Abs File--- > type RelFile = Path Rel File--- > type AbsDir = Path Abs Dir--- > type RelDir = Path Rel Dir--- >--- > type AbsPath fd = Path Abs fd--- > type RelPath fd = Path Rel fd--- > type FilePath ar = Path ar File--- > type DirPath ar = Path ar Dir------ The type of the 'combine' (aka '</>') function gives the idea:------ > (</>) :: DirPath ar -> RelPath fd -> Path ar fd------ Together this enables us to give more meaningful types to--- a lot of the functions, and (hopefully) catch a bunch more--- errors at compile time.------ Overloaded string literals are supported, so with the @OverloadedStrings@--- extension enabled, you can:------ > f :: FilePath ar--- > f = "tmp" </> "someFile" <.> "ext"------ If you don't want to use @OverloadedStrings@, you can use the construction fns:------ > f :: FilePath ar--- > f = asDirPath "tmp" </> asFilePath "someFile" <.> "ext"------ or...------ > f :: FilePath ar--- > f = asPath "tmp" </> asPath "someFile" <.> "ext"------ or just...------ > f :: FilePath ar--- > f = asPath "tmp/someFile.ext"------ One point to note is that whether one of these is interpreted as--- an absolute or a relative path depends on the type at which it is--- used:------ > *System.Path> f :: AbsFile--- > /tmp/someFile.ext--- > *System.Path> f :: RelFile--- > tmp/someFile.ext------ You will typically want to import as follows:------ > import Prelude hiding (FilePath)--- > import System.Path--- > import System.Path.Directory--- > import System.Path.IO------ The basic API (and properties satisfied) are heavily influenced--- by Neil Mitchell's "System.FilePath" module.--------- Ben Moseley - (c) 2009-2010-----#if defined(mingw32_HOST_OS) || defined(__MINGW32__)-module System.Path(module System.Path.Windows) where-import System.Path.Windows-#else-module System.Path(module System.Path.Posix) where-import System.Path.Posix-#endif-+module System.Path (+ module System.Path.Host,+ module System.Path.Generic,+ ) where +import System.Path.Host+import System.Path.Generic hiding (+ System, Path,+ AbsFile, RelFile, AbsDir, RelDir,+ AbsPath, RelPath, FilePath, DirPath,+ AbsOrRelFile, AbsOrRelDir, AbsFileOrDir, RelFileOrDir,+ AbsOrRelPath, FileOrDirPath, AbsOrRelFileOrDir,+ asPath,+ asRelFile, asRelDir, asAbsFile, asAbsDir,+ asRelPath, asAbsPath, asFilePath, asDirPath,+ isAbsoluteString, isRelativeString, equalFilePath,+ path, maybePath,+ relFile, relDir, absFile, absDir,+ relPath, absPath, filePath, dirPath,+ rootDir, currentDir, emptyFile,+ toString,+ )
src/System/Path/Directory.hs view
@@ -63,7 +63,13 @@ where -import System.Path+import qualified System.Path as Path+import System.Path (+ Path, AbsOrRelClass, FileOrDirClass, path,+ AbsPath, AbsDir, AbsFile, RelPath, RelDir, RelFile,+ DirPath, FilePath, absDir, (</>),+ )+ import System.Path.ModificationTime (convertTime) import Data.Time (UTCTime) @@ -73,6 +79,7 @@ import Control.Applicative ((<$>)) import Data.List (partition)+import Data.Tuple.HT (mapPair) import Prelude hiding (FilePath) @@ -80,32 +87,37 @@ ------------------------------------------------------------------------ -- Actions on directories -createDirectory :: AbsRelClass ar => DirPath ar -> IO ()-createDirectory = SD.createDirectory . getPathString+createDirectory :: AbsOrRelClass ar => DirPath ar -> IO ()+createDirectory = SD.createDirectory . Path.toString -createDirectoryIfMissing :: AbsRelClass ar => Bool -> DirPath ar -> IO ()-createDirectoryIfMissing flag = SD.createDirectoryIfMissing flag . getPathString+createDirectoryIfMissing :: AbsOrRelClass ar => Bool -> DirPath ar -> IO ()+createDirectoryIfMissing flag = SD.createDirectoryIfMissing flag . Path.toString -removeDirectory :: AbsRelClass ar => DirPath ar -> IO ()-removeDirectory = SD.removeDirectory . getPathString+removeDirectory :: AbsOrRelClass ar => DirPath ar -> IO ()+removeDirectory = SD.removeDirectory . Path.toString -removeDirectoryRecursive :: AbsRelClass ar => DirPath ar -> IO ()-removeDirectoryRecursive = SD.removeDirectoryRecursive . getPathString+removeDirectoryRecursive :: AbsOrRelClass ar => DirPath ar -> IO ()+removeDirectoryRecursive = SD.removeDirectoryRecursive . Path.toString -renameDirectory :: (AbsRelClass ar1, AbsRelClass ar2) => DirPath ar1 -> DirPath ar2 -> IO ()-renameDirectory p1 p2 = SD.renameDirectory (getPathString p1) (getPathString p2)+renameDirectory ::+ (AbsOrRelClass ar1, AbsOrRelClass ar2) => DirPath ar1 -> DirPath ar2 -> IO ()+renameDirectory p1 p2 =+ SD.renameDirectory (Path.toString p1) (Path.toString p2) --- | An alias for 'relDirectoryContents'.-getDirectoryContents :: AbsRelClass ar => DirPath ar -> IO ([RelDir], [RelFile])-getDirectoryContents = relDirectoryContents+-- | Retrieve the contents of a directory without any directory prefixes.+-- In contrast to 'System.Directory.getDirectoryContents',+-- exclude special directories \".\" and \"..\".+getDirectoryContents :: AbsOrRelClass ar => DirPath ar -> IO [Path.RelFileOrDir]+getDirectoryContents dir =+ map Path.path <$> plainDirectoryContents dir -- | Retrieve the contents of a directory path (which may be relative) as absolute paths-absDirectoryContents :: AbsRelClass ar => DirPath ar -> IO ([AbsDir], [AbsFile])+absDirectoryContents ::+ AbsOrRelClass ar => DirPath ar -> IO ([AbsDir], [AbsFile]) absDirectoryContents p = do- cd <- asAbsDir <$> SD.getCurrentDirectory- let dir = absRel id (cd </>) p- (rds, rfs) <- relDirectoryContents dir- return (map (dir </>) rds, map (dir </>) rfs)+ cd <- absDir <$> SD.getCurrentDirectory+ let dir = Path.absRel id (cd </>) p+ mapPair (map (dir </>), map (dir </>)) <$> relDirectoryContents dir -- | Returns paths relative /to/ the supplied (abs or relative) directory path. -- eg (for current working directory of @\/somewhere\/cwd\/@):@@ -113,97 +125,105 @@ -- > show (relDirectoryContents "d/e/f/") == (["subDir1A","subDir1B"], -- > ["file1A","file1B"]) ---relDirectoryContents :: AbsRelClass ar => DirPath ar -> IO ([RelDir], [RelFile])+relDirectoryContents ::+ AbsOrRelClass ar => DirPath ar -> IO ([RelDir], [RelFile]) relDirectoryContents dir = do- filenames <- filter (not . flip elem [".",".."]) <$> SD.getDirectoryContents (getPathString dir)- dirFlags <- mapM (doesDirectoryExist . (dir </>) . asRelPath) filenames- let fileinfo = zip filenames dirFlags- (dirs, files) = partition snd fileinfo- return (map (combine currentDir . asRelDir . fst) dirs,- map (combine currentDir . asRelFile . fst) files)+ filenames <- plainDirectoryContents dir+ mapPair (map (Path.relDir . fst), map (Path.relFile . fst)) .+ partition snd . zip filenames+ <$> mapM (doesDirectoryExist . (dir </>) . Path.relPath) filenames +plainDirectoryContents :: AbsOrRelClass ar => DirPath ar -> IO [String]+plainDirectoryContents dir =+ filter (not . flip elem [".",".."]) <$>+ SD.getDirectoryContents (Path.toString dir)+ -- | A convenient alternative to 'relDirectoryContents' if you only want files.-filesInDir :: AbsRelClass ar => DirPath ar -> IO [RelFile]+filesInDir :: AbsOrRelClass ar => DirPath ar -> IO [RelFile] filesInDir dir = snd <$> relDirectoryContents dir -- | A convenient alternative to 'relDirectoryContents' if you only want directories.-dirsInDir :: AbsRelClass ar => DirPath ar -> IO [RelDir]+dirsInDir :: AbsOrRelClass ar => DirPath ar -> IO [RelDir] dirsInDir dir = fst <$> relDirectoryContents dir getCurrentDirectory :: IO AbsDir-getCurrentDirectory = asAbsDir <$> SD.getCurrentDirectory+getCurrentDirectory = absDir <$> SD.getCurrentDirectory -setCurrentDirectory :: AbsRelClass ar => DirPath ar -> IO ()-setCurrentDirectory = SD.setCurrentDirectory . getPathString+setCurrentDirectory :: AbsOrRelClass ar => DirPath ar -> IO ()+setCurrentDirectory = SD.setCurrentDirectory . Path.toString ------------------------------------------------------------------------ -- Pre-defined directories getHomeDirectory :: IO AbsDir-getHomeDirectory = asAbsDir <$> SD.getHomeDirectory+getHomeDirectory = absDir <$> SD.getHomeDirectory getAppUserDataDirectory :: String -> IO AbsDir-getAppUserDataDirectory user = asAbsDir <$> SD.getAppUserDataDirectory user+getAppUserDataDirectory user = absDir <$> SD.getAppUserDataDirectory user getUserDocumentsDirectory :: IO AbsDir-getUserDocumentsDirectory = asAbsDir <$> SD.getUserDocumentsDirectory+getUserDocumentsDirectory = absDir <$> SD.getUserDocumentsDirectory getTemporaryDirectory :: IO AbsDir-getTemporaryDirectory = asAbsDir <$> SD.getTemporaryDirectory+getTemporaryDirectory = absDir <$> SD.getTemporaryDirectory ------------------------------------------------------------------------ -- Actions on files -removeFile :: AbsRelClass ar => FilePath ar -> IO ()-removeFile = SD.removeFile . getPathString+removeFile :: AbsOrRelClass ar => FilePath ar -> IO ()+removeFile = SD.removeFile . Path.toString -renameFile :: (AbsRelClass ar1, AbsRelClass ar2) => FilePath ar1 -> FilePath ar2 -> IO ()-renameFile p1 p2 = SD.renameFile (getPathString p1) (getPathString p2)+renameFile ::+ (AbsOrRelClass ar1, AbsOrRelClass ar2) =>+ FilePath ar1 -> FilePath ar2 -> IO ()+renameFile p1 p2 = SD.renameFile (Path.toString p1) (Path.toString p2) -copyFile :: (AbsRelClass ar1, AbsRelClass ar2) => FilePath ar1 -> FilePath ar2 -> IO ()-copyFile p1 p2 = SD.copyFile (getPathString p1) (getPathString p2)+copyFile ::+ (AbsOrRelClass ar1, AbsOrRelClass ar2) =>+ FilePath ar1 -> FilePath ar2 -> IO ()+copyFile p1 p2 = SD.copyFile (Path.toString p1) (Path.toString p2) canonicalizePath ::- (AbsRelClass ar, FileDirClass fd) => Path ar fd -> IO (AbsPath fd)-canonicalizePath p = asPath <$> SD.canonicalizePath (getPathString p)+ (AbsOrRelClass ar, FileOrDirClass fd) => Path ar fd -> IO (AbsPath fd)+canonicalizePath p = path <$> SD.canonicalizePath (Path.toString p) makeRelativeToCurrentDirectory ::- (AbsRelClass ar, FileDirClass fd) => Path ar fd -> IO (RelPath fd)+ (AbsOrRelClass ar, FileOrDirClass fd) => Path ar fd -> IO (RelPath fd) makeRelativeToCurrentDirectory p =- asPath <$> SD.makeRelativeToCurrentDirectory (getPathString p)+ path <$> SD.makeRelativeToCurrentDirectory (Path.toString p) findExecutable :: String -> IO (Maybe AbsFile)-findExecutable s = fmap asPath <$> SD.findExecutable s+findExecutable s = fmap path <$> SD.findExecutable s ------------------------------------------------------------------------ -- Existence tests -doesFileExist :: AbsRelClass ar => FilePath ar -> IO Bool-doesFileExist = SD.doesFileExist . getPathString+doesFileExist :: AbsOrRelClass ar => FilePath ar -> IO Bool+doesFileExist = SD.doesFileExist . Path.toString -doesDirectoryExist :: AbsRelClass ar => DirPath ar -> IO Bool-doesDirectoryExist = SD.doesDirectoryExist . getPathString+doesDirectoryExist :: AbsOrRelClass ar => DirPath ar -> IO Bool+doesDirectoryExist = SD.doesDirectoryExist . Path.toString ------------------------------------------------------------------------ -- Permissions getPermissions ::- (AbsRelClass ar, FileDirClass fd) => Path ar fd -> IO Permissions-getPermissions p = SD.getPermissions (getPathString p)+ (AbsOrRelClass ar, FileOrDirClass fd) => Path ar fd -> IO Permissions+getPermissions p = SD.getPermissions (Path.toString p) setPermissions ::- (AbsRelClass ar, FileDirClass fd) => Path ar fd -> Permissions -> IO ()-setPermissions p perms = SD.setPermissions (getPathString p) perms+ (AbsOrRelClass ar, FileOrDirClass fd) => Path ar fd -> Permissions -> IO ()+setPermissions p perms = SD.setPermissions (Path.toString p) perms ------------------------------------------------------------------------ -- Timestamps getModificationTime ::- (AbsRelClass ar, FileDirClass fd) => Path ar fd -> IO UTCTime-getModificationTime p = convertTime <$> SD.getModificationTime (getPathString p)+ (AbsOrRelClass ar, FileOrDirClass fd) => Path ar fd -> IO UTCTime+getModificationTime p = convertTime <$> SD.getModificationTime (Path.toString p)
+ src/System/Path/Generic.hs view
@@ -0,0 +1,22 @@+{- |+This module provides type-safe access to filepath manipulations+independent from the operating system.++Normally you would import 'System.Path'+since this contains types fixed to your host system+and otherwise generic functions.+However, importing this explicitly+allows for manipulation of non-native paths.+-}+module System.Path.Generic (+ module System.Path.Internal,+ Core.System,+ ) where++import qualified System.Path.Internal as Core+import System.Path.Internal hiding (+ System(..),+ extSeparator, isExtSeparator,+ searchPathSeparator, isSearchPathSeparator,+ testAll,+ )
src/System/Path/IO.hs view
@@ -90,13 +90,14 @@ where -import System.Path+import qualified System.Path as Path+import System.Path (AbsOrRelClass, DirPath, FilePath, AbsFile, RelFile) import qualified System.IO as SIO import System.IO (IOMode, Handle) -import Control.Arrow (first) import Control.Applicative ((<$>))+import Data.Tuple.HT (mapFst) import Prelude hiding (FilePath, readFile, writeFile, appendFile) @@ -104,29 +105,37 @@ ------------------------------------------------------------------------ -- Covers for System.IO functions -withFile :: AbsRelClass ar => FilePath ar -> IOMode -> (Handle -> IO r) -> IO r-withFile f = SIO.withFile (getPathString f)+withFile ::+ AbsOrRelClass ar => FilePath ar -> IOMode -> (Handle -> IO r) -> IO r+withFile f = SIO.withFile (Path.toString f) -openFile :: AbsRelClass ar => FilePath ar -> IOMode -> IO Handle-openFile f = SIO.openFile (getPathString f)+openFile :: AbsOrRelClass ar => FilePath ar -> IOMode -> IO Handle+openFile f = SIO.openFile (Path.toString f) -readFile :: AbsRelClass ar => FilePath ar -> IO String-readFile f = SIO.readFile (getPathString f)+readFile :: AbsOrRelClass ar => FilePath ar -> IO String+readFile f = SIO.readFile (Path.toString f) -writeFile :: AbsRelClass ar => FilePath ar -> String -> IO ()-writeFile f = SIO.writeFile (getPathString f)+writeFile :: AbsOrRelClass ar => FilePath ar -> String -> IO ()+writeFile f = SIO.writeFile (Path.toString f) -appendFile :: AbsRelClass ar => FilePath ar -> String -> IO ()-appendFile f = SIO.appendFile (getPathString f)+appendFile :: AbsOrRelClass ar => FilePath ar -> String -> IO ()+appendFile f = SIO.appendFile (Path.toString f) -withBinaryFile :: AbsRelClass ar => FilePath ar -> IOMode -> (Handle -> IO r) -> IO r-withBinaryFile f = SIO.withBinaryFile (getPathString f)+withBinaryFile ::+ AbsOrRelClass ar => FilePath ar -> IOMode -> (Handle -> IO r) -> IO r+withBinaryFile f = SIO.withBinaryFile (Path.toString f) -openBinaryFile :: AbsRelClass ar => FilePath ar -> IOMode -> IO Handle-openBinaryFile f = SIO.openBinaryFile (getPathString f)+openBinaryFile :: AbsOrRelClass ar => FilePath ar -> IOMode -> IO Handle+openBinaryFile f = SIO.openBinaryFile (Path.toString f) -openTempFile :: AbsRelClass ar => DirPath ar -> RelFile -> IO (AbsFile, Handle)-openTempFile f template = first asAbsFile <$> SIO.openTempFile (getPathString f) (getPathString template)+openTempFile ::+ AbsOrRelClass ar => DirPath ar -> RelFile -> IO (AbsFile, Handle)+openTempFile f template =+ mapFst Path.absFile <$>+ SIO.openTempFile (Path.toString f) (Path.toString template) -openBinaryTempFile :: AbsRelClass ar => DirPath ar -> RelFile -> IO (AbsFile, Handle)-openBinaryTempFile f template = first asAbsFile <$> SIO.openBinaryTempFile (getPathString f) (getPathString template)+openBinaryTempFile ::+ AbsOrRelClass ar => DirPath ar -> RelFile -> IO (AbsFile, Handle)+openBinaryTempFile f template =+ mapFst Path.absFile <$>+ SIO.openBinaryTempFile (Path.toString f) (Path.toString template)
src/System/Path/Internal.hs view
@@ -1,1211 +1,1833 @@---- LANGUAGE pragmas need to go in System.Path.[Windows|Posix]-module System.Path.MODULE_NAME-(- -- * The main filepath (& dirpath) abstract type- Path, -- kept abstract-- -- * Phantom Types- Abs,- Rel,- File,- Dir,-- -- * Type Synonyms- AbsFile,- RelFile,- AbsDir,- RelDir,- AbsPath,- RelPath,- FilePath,- DirPath,-- -- * Classes- AbsRelClass(..),- FileDirClass(..),-- -- * Path to String conversion- getPathString,-- -- * Constants- rootDir,- currentDir,-- -- * Unchecked Construction Functions- asPath,- asRelFile,- asRelDir,- asAbsFile,- asAbsDir,- asRelPath,- asAbsPath,- asFilePath,- asDirPath,-- -- * Checked Construction Functions- mkPathAbsOrRel,- mkPathFileOrDir,- mkAbsPath,- mkAbsPathFromCwd,-- -- * Basic Manipulation Functions- (</>),- (<.>),- addExtension,- combine,- dropExtension,- dropExtensions,- dropFileName,- replaceExtension,- replaceBaseName,- replaceDirectory,- replaceFileName,- splitExtension,- splitExtensions,- splitFileName,- takeBaseName,- takeDirectory,- takeExtension,- takeExtensions,- takeFileName,-- -- * Auxillary Manipulation Functions- equalFilePath,- joinPath,- normalise,- splitPath,- makeRelative,- makeAbsolute,- makeAbsoluteFromCwd,- genericMakeAbsolute,- genericMakeAbsoluteFromCwd,- pathMap,-- -- * Path Predicates- isAbsolute,- isAbsoluteString,- isRelative,- isRelativeString,- hasAnExtension,- hasExtension,-- -- * Separators- addTrailingPathSeparator,- dropTrailingPathSeparator,- extSeparator,- hasTrailingPathSeparator,- pathSeparator,- pathSeparators,- searchPathSeparator,- isExtSeparator,- isPathSeparator,- isSearchPathSeparator,-- -- * Generic Manipulation Functions- genericAddExtension,- genericDropExtension,- genericDropExtensions,- genericSplitExtension,- genericSplitExtensions,- genericTakeExtension,- genericTakeExtensions-)--where--import qualified System.Directory as SD--import Control.Arrow (first, second, (|||), (***))-import Control.Monad (guard, mplus)-import Control.Applicative ((<$>))-import Control.DeepSeq (NFData(rnf))-import Data.List (isSuffixOf, isPrefixOf, stripPrefix, intersperse)-import Data.String (IsString(fromString))-import Data.Maybe (fromMaybe, maybeToList)-import Data.Char (toLower, isAlpha, isSpace)--import Text.Printf (printf)--import qualified Test.QuickCheck as QC-import Test.QuickCheck- (Gen, Property, property, Arbitrary(arbitrary),- oneof, frequency, quickCheck)--import Prelude hiding (FilePath)------------------------------------------------------------------------------ Types--newtype Abs = Abs String deriving (Eq, Ord)-data Rel = Rel deriving (Eq, Ord)--newtype File = File PathComponent deriving (Eq, Ord)-data Dir = Dir deriving (Eq, Ord)---- | This is the main filepath abstract datatype-data Path ar fd = Path ar [PathComponent] fd--instance (AbsRelClass ar, FileDirClass fd) => Eq (Path ar fd) where- Path ar0 pcs0 fd0 == Path ar1 pcs1 fd1 =- (WrapAbsRel ar0, pcs0, WrapFileDir fd0)- ==- (WrapAbsRel ar1, pcs1, WrapFileDir fd1)--instance (AbsRelClass ar, FileDirClass fd) => Ord (Path ar fd) where- compare (Path ar0 pcs0 fd0) (Path ar1 pcs1 fd1) =- compare- (WrapAbsRel ar0, pcs0, WrapFileDir fd0)- (WrapAbsRel ar1, pcs1, WrapFileDir fd1)---newtype WrapAbsRel ar = WrapAbsRel {unwrapAbsRel :: ar}--instance (AbsRelClass ar) => Eq (WrapAbsRel ar) where- (==) = switchRelation switchAbsRel unwrapAbsRel (==) (==)--instance (AbsRelClass ar) => Ord (WrapAbsRel ar) where- compare = switchRelation switchAbsRel unwrapAbsRel compare compare---newtype WrapFileDir fd = WrapFileDir {unwrapFileDir :: fd}--instance (FileDirClass fd) => Eq (WrapFileDir fd) where- (==) = switchRelation switchFileDir unwrapFileDir (==) (==)--instance (FileDirClass fd) => Ord (WrapFileDir fd) where- compare = switchRelation switchFileDir unwrapFileDir compare compare---newtype Relation res a = Relation {runRelation :: a -> a -> res}--switchRelation ::- (Relation res a -> Relation res b -> Relation res c) ->- (wrapped -> c) ->- (a -> a -> res) ->- (b -> b -> res) ->- wrapped -> wrapped -> res-switchRelation switch unwrap fFile fDir ar0 ar1 =- runRelation- (switch (Relation fFile) (Relation fDir))- (unwrap ar0) (unwrap ar1)---newtype PathComponent = PathComponent String--instance Eq PathComponent where- PathComponent x == PathComponent y =- if isPosix- then x==y- else map toLower x == map toLower y--instance Ord PathComponent where- compare (PathComponent x) (PathComponent y) =- if isPosix- then compare x y- else compare (map toLower x) (map toLower y)---type AbsFile = Path Abs File-type RelFile = Path Rel File-type AbsDir = Path Abs Dir-type RelDir = Path Rel Dir--type AbsPath fd = Path Abs fd-type RelPath fd = Path Rel fd-type FilePath ar = Path ar File-type DirPath ar = Path ar Dir--instance NFData PathComponent where- rnf (PathComponent pc) = rnf pc--instance NFData Abs where- rnf (Abs drive) = rnf drive--instance NFData Rel where- rnf Rel = ()--instance NFData File where- rnf (File pc) = rnf pc--instance NFData Dir where- rnf Dir = ()--instance (AbsRelClass ar, FileDirClass fd) => NFData (Path ar fd) where- rnf (Path ar pcs fd) =- rnf (absRelPlain rnf rnf ar, pcs, fileDirPlain rnf rnf fd)--absRelPlain :: (AbsRelClass ar) => (Abs -> a) -> (Rel -> a) -> ar -> a-absRelPlain fAbs fRel =- runFuncArg $ switchAbsRel (FuncArg fAbs) (FuncArg fRel)--fileDirPlain :: (FileDirClass fd) => (File -> a) -> (Dir -> a) -> fd -> a-fileDirPlain fFile fDir =- runFuncArg $ switchFileDir (FuncArg fFile) (FuncArg fDir)--newtype FuncArg b a = FuncArg {runFuncArg :: a -> b}---- I don't think this basic type of fold is appropriate for a nested datatype--- pathFold :: a -> (a -> String -> a) -> Path ar fd -> a--- pathFold pr f PathRoot = pr--- pathFold pr f (FileDir d pc) = f (pathFold pr f d) (unPathComponent pc)---- | Map over the components of the path.------ >> Posix.pathMap (map toLower) "/tmp/Reports/SpreadSheets" == Posix.asAbsDir "/tmp/reports/spreadsheets"-pathMap :: (FileDirClass fd) => (String -> String) -> Path ar fd -> Path ar fd-pathMap f (Path ar pcs fd) = Path ar (map (pcMap f) pcs) (fdMap f fd)--newtype FDMap ar fd = FDMap {runFDMap :: fd -> fd}--fdMap :: (FileDirClass fd) => (String -> String) -> fd -> fd-fdMap f =- runFDMap $- switchFileDir (FDMap $ \(File pc) -> File $ pcMap f pc) (FDMap id)--pcMap :: (String -> String) -> PathComponent -> PathComponent-pcMap f (PathComponent s) = PathComponent (f s)------------------------------------------------------------------------------ Type classes and machinery for switching on Abs/Rel and File/Dir---- | This class provides a way to prevent other modules--- from making further 'AbsRelClass' or 'FileDirClass'--- instances-class Private p-instance Private Abs-instance Private Rel-instance Private File-instance Private Dir---- | This class allows selective behaviour for absolute and--- relative paths and is mostly for internal use.-class Private ar => AbsRelClass ar where- -- | See <https://wiki.haskell.org/Closed_world_instances>- -- for the used technique.- switchAbsRel :: f Abs -> f Rel -> f ar- -- | Will become a top-level function in future- absRel :: (AbsPath fd -> a) -> (RelPath fd -> a) -> Path ar fd -> a- absRel f g = runAbsRel $ switchAbsRel (AbsRel f) (AbsRel g)--newtype AbsRel fd a ar = AbsRel {runAbsRel :: Path ar fd -> a}--instance AbsRelClass Abs where switchAbsRel f _g = f-instance AbsRelClass Rel where switchAbsRel _f g = g---- | This class allows selective behaviour for file and--- directory paths and is mostly for internal use.-class Private fd => FileDirClass fd where- switchFileDir :: f File -> f Dir -> f fd- -- | Will become a top-level function in future- fileDir :: (FilePath ar -> a) -> (DirPath ar -> a) -> Path ar fd -> a- fileDir f g = runFileDir $ switchFileDir (FileDir f) (FileDir g)--newtype FileDir ar a fd = FileDir {runFileDir :: Path ar fd -> a}--instance FileDirClass File where switchFileDir f _g = f-instance FileDirClass Dir where switchFileDir _f g = g----- | Currently not exported-_pathAbsRel :: AbsRelClass ar => Path ar fd -> Either (AbsPath fd) (RelPath fd)-_pathAbsRel = absRel Left Right---- | Currently not exported-_pathFileDir :: FileDirClass fd => Path ar fd -> Either (FilePath ar) (DirPath ar)-_pathFileDir = fileDir Left Right----------------------------------------------------------------------------- Read & Show instances---- >> show (Posix.rootDir </> "bla" </> Posix.asRelFile "blub") == "rootDir </> \"bla\" </> \"blub\""--- >> show (Just (Posix.rootDir </> "bla" </> Posix.asRelFile "blub")) == "Just (rootDir </> \"bla\" </> \"blub\")"--- >> show (Posix.currentDir </> "bla" </> Posix.asRelFile "blub") == "currentDir </> \"bla\" </> \"blub\""--- >> show (Just (Posix.currentDir </> "bla" </> Posix.asRelFile "blub")) == "Just (currentDir </> \"bla\" </> \"blub\")"--- >> show (Windows.asAbsDir "c:" Windows.</> "bla" Windows.</> Windows.asRelFile "blub") == "asAbsDir \"c:\" </> \"bla\" </> \"blub\""--- >> show (Just (Windows.asAbsDir "c:\\" Windows.</> "bla" Windows.</> Windows.asRelFile "blub")) == "Just (asAbsDir \"c:\" </> \"bla\" </> \"blub\")"-instance (AbsRelClass ar, FileDirClass fd) => Show (Path ar fd) where- showsPrec d x =- case pathComponents x of- (ar, pcs) ->- showParen (d>9) $- foldr (.) id $- intersperse- (showChar ' ' .- showString combineOperator . showChar ' ') $- absRelPlain- (\(Abs drive) ->- if null drive- then showString rootName- else showString absDirName .- showString drive .- showChar '"')- (const $ showString currentName)- ar :- map (\(PathComponent pc) -> shows pc) pcs---- >> let path = Posix.rootDir </> "bla" </> Posix.asRelFile "blub" in read (show path) == path--- >> let path = Just (Posix.rootDir </> "bla" </> Posix.asRelFile "blub") in read (show path) == path--- >> let path = Posix.currentDir </> "bla" </> Posix.asRelFile "blub" in read (show path) == path--- >> let path = Just (Posix.currentDir </> "bla" </> Posix.asRelFile "blub") in read (show path) == path--- >> let path = Windows.rootDir Windows.</> "bla" Windows.</> Windows.asRelFile "blub" in read (show path) == path--- >> let path = Just (Windows.rootDir Windows.</> "bla" Windows.</> Windows.asRelFile "blub") in read (show path) == path-instance (AbsRelClass ar, FileDirClass fd) => Read (Path ar fd) where- readsPrec d = readParen (d>9) $ \str ->- let go :: ReadS [PathComponent]- go s0 =- case stripPrefix combineOperator $ dropWhile isSpace s0 of- Nothing -> [([], s0)]- Just s1 -> do- (pc, s2) <- reads s1- (pcs, s3) <- go s2- return (PathComponent pc : pcs, s3)- in do- (ar, s0) <- maybeToList $ readsSplitDrive $ dropWhile isSpace str- (pcs, s1) <- go s0- path <- maybeToList $ maybePathFromComponents ar pcs- return (path, s1)--newtype- ReadsSplitDrive ar =- ReadsSplitDrive {runReadsSplitDrive :: Maybe (ar, String)}--readsSplitDrive :: (AbsRelClass ar) => String -> Maybe (ar, String)-readsSplitDrive str0 =- runReadsSplitDrive $- switchAbsRel- (ReadsSplitDrive $- (fmap ((,) (Abs "")) $ stripPrefix rootName str0)- `mplus`- do str1 <- stripPrefix absDirName str0- (drive, '"':str2) <- Just $ break ('"'==) str1- return (Abs drive, str2))- (ReadsSplitDrive $- fmap ((,) Rel) $ stripPrefix currentName str0)---- | Convert the 'Path' into a plain 'String' as required for OS calls.-getPathString :: (AbsRelClass ar, FileDirClass fd) => Path ar fd -> String-getPathString = flip getPathStringS ""--getPathStringS :: (AbsRelClass ar, FileDirClass fd) => Path ar fd -> ShowS-getPathStringS x =- case pathComponents x of- (ar, []) ->- absRelPlain- (\(Abs drive) -> showString drive . showChar pathSeparator)- (const $ showString currentDirComponent) ar- (ar, pcs) ->- foldr (.) id $ intersperse (showChar pathSeparator) $- absRelPlain (\(Abs drive) -> (showString drive :)) (const id) ar $- map (\(PathComponent pc) -> showString pc) pcs--prop_asPath_getPathString :: AbsFile -> Property-prop_asPath_getPathString p = property $ p == asPath (getPathString p)------------------------------------------------------------------------------ Windows / Posix--isPosix :: Bool-isPosix = not isWindows--isWindows :: Bool-isWindows = IS_WINDOWS----------------------------------------------------------------------------- Constants--rootDir :: AbsDir-rootDir = Path (Abs "") [] Dir--currentDir :: RelDir-currentDir = Path Rel [] Dir--rootName :: String-rootName = "rootDir"--currentName :: String-currentName = "currentDir"--currentDirComponent :: String-currentDirComponent = "."--absDirName :: String-absDirName = "asAbsDir \""----------------------------------------------------------------------------- Unchecked Construction Functions--- NB - these construction functions are non-IO and do no checking!!---- | Use a 'String' as a 'Path' whose type is determined--- by its context.------ >> Posix.asPath "/tmp" == Posix.asAbsDir "/tmp"--- >> Posix.asPath "file.txt" == Posix.asRelFile "file.txt"--- >> Posix.isAbsolute (Posix.asAbsDir "/tmp")--- >> Posix.isRelative (Posix.asRelDir "/tmp")--- >> Posix.getPathString (Posix.asPath "/tmp" :: Posix.AbsDir) == "/tmp"--- >> Posix.getPathString (Posix.asPath "/tmp" :: Posix.RelDir) == "tmp"--- >> Windows.getPathString (Windows.asPath "\\tmp" :: Windows.AbsDir) == "\\tmp"--- >> Windows.getPathString (Windows.asPath "a:\\tmp" :: Windows.AbsDir) == "a:\\tmp"--- >> Windows.getPathString (Windows.asPath "tmp" :: Windows.RelDir) == "tmp"-asPath :: (AbsRelClass ar, FileDirClass fd) => String -> Path ar fd-asPath = uncurry mkPathFromComponents . mkPathComponents--newtype AbsRelDefault ar = AbsRelDefault {getAbsRelDefault :: ar}--absRelDefault :: (AbsRelClass ar) => ar-absRelDefault =- getAbsRelDefault $ switchAbsRel (AbsRelDefault $ Abs "") (AbsRelDefault Rel)----- | Use a 'String' as a 'RelFile'. No checking is done.------ >> Posix.getPathString (Posix.asRelFile "file.txt") == "file.txt"--- >> Posix.getPathString (Posix.asRelFile "/file.txt") == "file.txt"--- >> Posix.getPathString (Posix.asRelFile "tmp") == "tmp"--- >> Posix.getPathString (Posix.asRelFile "/tmp") == "tmp"-asRelFile :: String -> RelFile-asRelFile = asPath---- | Use a 'String' as a 'RelDir'. No checking is done.------ >> Posix.getPathString (Posix.asRelDir ".") == "."--- >> Posix.getPathString (Posix.asRelDir "file.txt") == "file.txt"--- >> Posix.getPathString (Posix.asRelDir "/file.txt") == "file.txt"--- >> Posix.getPathString (Posix.asRelDir "tmp") == "tmp"--- >> Posix.getPathString (Posix.asRelDir "/tmp") == "tmp"-asRelDir :: String -> RelDir-asRelDir = asPath---- | Use a 'String' as an 'AbsFile'. No checking is done.------ >> Posix.getPathString (Posix.asAbsFile "file.txt") == "/file.txt"--- >> Posix.getPathString (Posix.asAbsFile "/file.txt") == "/file.txt"--- >> Posix.getPathString (Posix.asAbsFile "tmp") == "/tmp"--- >> Posix.getPathString (Posix.asAbsFile "/tmp") == "/tmp"-asAbsFile :: String -> AbsFile-asAbsFile = asPath---- | Use a 'String' as an 'AbsDir'. No checking is done.------ >> Posix.getPathString (Posix.asAbsDir "file.txt") == "/file.txt"--- >> Posix.getPathString (Posix.asAbsDir "/file.txt") == "/file.txt"--- >> Posix.getPathString (Posix.asAbsDir "tmp") == "/tmp"--- >> Posix.getPathString (Posix.asAbsDir "/tmp") == "/tmp"-asAbsDir :: String -> AbsDir-asAbsDir = asPath---- | Use a 'String' as a 'RelPath fd'. No checking is done.-asRelPath :: (FileDirClass fd) => String -> RelPath fd-asRelPath = asPath---- | Use a 'String' as an 'AbsPath fd'. No checking is done.-asAbsPath :: (FileDirClass fd) => String -> AbsPath fd-asAbsPath = asPath---- | Use a 'String' as a 'FilePath ar'. No checking is done.-asFilePath :: (AbsRelClass ar) => String -> FilePath ar-asFilePath = asPath---- | Use a 'String' as a 'DirPath ar'. No checking is done.-asDirPath :: (AbsRelClass ar) => String -> DirPath ar-asDirPath = asPath---- | Allow use of OverloadedStrings if desired-instance- (AbsRelClass ar, FileDirClass fd) =>- IsString (Path ar fd) where fromString = asPath----------------------------------------------------------------------------- Checked Construction Functions---- | Examines the supplied string and constructs an absolute or--- relative path as appropriate.------ >> Posix.mkPathAbsOrRel "/tmp" == Left (Posix.asAbsDir "/tmp")--- >> Posix.mkPathAbsOrRel "tmp" == Right (Posix.asRelDir "tmp")--- >> Windows.mkPathAbsOrRel "\\tmp" == Left (Windows.asAbsDir "\\tmp")--- >> Windows.mkPathAbsOrRel "d:\\tmp" == Left (Windows.asAbsDir "d:\\tmp")--- >> Windows.mkPathAbsOrRel "tmp" == Right (Windows.asRelDir "tmp")-mkPathAbsOrRel ::- (FileDirClass fd) => String -> Either (AbsPath fd) (RelPath fd)-mkPathAbsOrRel s =- if isAbsoluteString s- then Left $ asAbsPath s- else Right $ asRelPath s---- | Searches for a file or directory with the supplied path string--- and returns a 'File' or 'Dir' path as appropriate. If neither exists--- at the supplied path, 'Nothing' is returned.-mkPathFileOrDir ::- AbsRelClass ar => String -> IO (Maybe (Either (FilePath ar) (DirPath ar)))-mkPathFileOrDir s = do- isfile <- SD.doesFileExist s- isdir <- SD.doesDirectoryExist s- case (isfile, isdir) of- (False, False) -> return Nothing- (True, False) -> return $ Just $ Left $ asPath s- (False, True ) -> return $ Just $ Right $ asPath s- (True, True ) -> ioError $ userError "mkPathFileOrDir - object type changed while checking"---- | Convert a 'String' into an 'AbsPath' by interpreting it as--- relative to the supplied directory if necessary.------ >> Posix.mkAbsPath "/tmp" "foo.txt" == Posix.asAbsFile "/tmp/foo.txt"--- >> Posix.mkAbsPath "/tmp" "/etc/foo.txt" == Posix.asAbsFile "/etc/foo.txt"-mkAbsPath :: (FileDirClass fd) => AbsDir -> String -> AbsPath fd-mkAbsPath d = (id ||| makeAbsolute d) . mkPathAbsOrRel---- | Convert a 'String' into an 'AbsPath' by interpreting it as--- relative to the cwd if necessary.-mkAbsPathFromCwd :: (FileDirClass fd) => String -> IO (AbsPath fd)-mkAbsPathFromCwd = (return ||| makeAbsoluteFromCwd) . mkPathAbsOrRel------------------------------------------------------------------------------ Internal Functions for PathComponent manipulation--mkPathFromComponents :: (FileDirClass fd) => ar -> [PathComponent] -> Path ar fd-mkPathFromComponents ar pcs =- switchFileDir- (fromMaybe (Path ar [] $ File $ PathComponent "") $- mkFilePathFromComponents ar pcs)- (mkDirPathFromComponents ar pcs)--maybePathFromComponents ::- (FileDirClass fd) => ar -> [PathComponent] -> Maybe (Path ar fd)-maybePathFromComponents ar pcs =- getFunctorPath $- switchFileDir- (FunctorPath $ mkFilePathFromComponents ar pcs)- (FunctorPath $ Just $ mkDirPathFromComponents ar pcs)--newtype- FunctorPath f ar fd =- FunctorPath {getFunctorPath :: f (Path ar fd)}--mkDirPathFromComponents :: ar -> [PathComponent] -> Path ar Dir-mkDirPathFromComponents ar pcs = Path ar pcs Dir--mkFilePathFromComponents :: ar -> [PathComponent] -> Maybe (Path ar File)-mkFilePathFromComponents _ [] = Nothing-mkFilePathFromComponents ar0 (q:qs) =- let mapPathDirs f ~(Path ar pcs fd) = Path ar (f pcs) fd- go p [] = Path ar0 [] (File p)- go p0 (p1:ps) = mapPathDirs (p0:) $ go p1 ps- in Just $ go q qs--mkPathComponents :: (AbsRelClass ar) => String -> (ar, [PathComponent])-mkPathComponents =- let go xs =- case break isPathSeparator $ dropWhile isPathSeparator xs of- ("","") -> []- (s,rest) -> s : go rest- split [] = (absRelDefault, [])- split (pc:pcs) =- second (map PathComponent) $- case splitDrive pc of- (drive, "") -> (drive, pcs)- (drive, pc0) -> (drive, pc0:pcs)- in split . go--newtype SplitDrive ar = SplitDrive {runSplitDrive :: (ar, String)}--splitDrive :: (AbsRelClass ar) => String -> (ar, String)-splitDrive str =- runSplitDrive $- switchAbsRel- (SplitDrive $ first Abs $- if isPosix- then ("", str)- else- case break (':'==) str of- (drive, ':':rest) -> (drive++":", rest)- _ -> ("", str))- (SplitDrive (Rel, str))--pathComponents :: (FileDirClass fd) => Path ar fd -> (ar, [PathComponent])-pathComponents (Path ar pcs fd) = (ar, pcs ++ fileDirComponent fd)--fileDirComponent :: (FileDirClass fd) => fd -> [PathComponent]-fileDirComponent = fileDirPlain (\(File pc) -> [pc]) (\Dir -> [])--prop_mkPathFromComponents_pathComponents :: AbsDir -> Property-prop_mkPathFromComponents_pathComponents p =- property $ uncurry mkPathFromComponents (pathComponents p) == p------------------------------------------------------------------------------- Basic Manipulation Functions--combineOperator :: String-combineOperator = "</>"---- | Infix variant of 'combine'.------ >> Posix.getPathString (Posix.asAbsDir "/tmp" </> Posix.asRelFile "file.txt") == "/tmp/file.txt"--- >> Posix.getPathString (Posix.asAbsDir "/tmp" </> Posix.asRelDir "dir" </> Posix.asRelFile "file.txt") == "/tmp/dir/file.txt"--- >> Posix.getPathString (Posix.asRelDir "dir" </> Posix.asRelFile "file.txt") == "dir/file.txt"--- >> Windows.getPathString (Windows.asAbsDir "\\tmp" Windows.</> Windows.asRelFile "file.txt") == "\\tmp\\file.txt"--- >> Windows.getPathString (Windows.asAbsDir "c:\\tmp" Windows.</> Windows.asRelFile "file.txt") == "c:\\tmp\\file.txt"--- >> Windows.getPathString (Windows.asAbsDir "c:" Windows.</> Windows.asRelDir "tmp" Windows.</> Windows.asRelFile "file.txt") == "c:\\tmp\\file.txt"--- >> Windows.getPathString (Windows.asRelDir "dir" Windows.</> Windows.asRelFile "file.txt") == "dir\\file.txt"-(</>) :: DirPath ar -> RelPath fd -> Path ar fd-(Path ar pcs0 Dir) </> (Path Rel pcs1 fd) = Path ar (pcs0 ++ pcs1) fd---- | Infix variant of 'addExtension'.--- We only allow files (and not directories) to have extensions added--- by this function. This is because it's the vastly common case and--- an attempt to add one to a directory will - more often than not ---- represent an error.--- We don't however want to prevent the corresponding operation on--- directories, and so we provide a function that is more flexible:--- 'genericAddExtension'.-(<.>) :: FilePath ar -> String -> FilePath ar-Path ar pcs (File pc) <.> ext = Path ar pcs (File $ addExtensionPC pc ext)---- | Add an extension, even if there is already one there.--- E.g. @addExtension \"foo.txt\" \"bat\" -> \"foo.txt.bat\"@.------ >> Posix.addExtension (Posix.asRelFile "file.txt") "bib" == "file.txt.bib"--- >> Posix.addExtension (Posix.asRelFile "file.") ".bib" == "file..bib"--- >> Posix.addExtension (Posix.asRelFile "file") ".bib" == "file.bib"--- >> Posix.addExtension (Posix.asRelFile "") "bib" == ".bib"--- >> Posix.addExtension (Posix.asRelFile "") ".bib" == ".bib"--- >> Posix.takeFileName (Posix.addExtension (Posix.asRelFile "") "ext") == ".ext"-addExtension :: FilePath ar -> String -> FilePath ar-addExtension = (<.>)---- | Join an (absolute or relative) directory path with a relative--- (file or directory) path to form a new path.-combine :: DirPath ar -> RelPath fd -> Path ar fd-combine = (</>)----- | Remove last extension, and the \".\" preceding it.------ >> Posix.dropExtension x == fst (Posix.splitExtension x)-dropExtension :: FilePath ar -> FilePath ar-dropExtension = fst . splitExtension---- | Drop all extensions------ >> not $ Posix.hasAnExtension (Posix.dropExtensions x)-dropExtensions :: FilePath ar -> FilePath ar-dropExtensions = fst . splitExtensions---- | Synonym for 'takeDirectory'-dropFileName :: FilePath ar -> DirPath ar-dropFileName = fst . splitFileName----- | Set the extension of a file, overwriting one if already present.------ >> Posix.replaceExtension (Posix.asRelFile "file.txt") ".bob" == "file.bob"--- >> Posix.replaceExtension (Posix.asRelFile "file.txt") "bob" == "file.bob"--- >> Posix.replaceExtension (Posix.asRelFile "file") ".bob" == "file.bob"--- >> Posix.replaceExtension (Posix.asRelFile "file.txt") "" == "file"--- >> Posix.replaceExtension (Posix.asRelFile "file.fred.bob") "txt" == "file.fred.txt"-replaceExtension :: FilePath ar -> String -> FilePath ar-replaceExtension p ext = dropExtension p <.> ext--replaceBaseName :: FilePath ar -> String -> FilePath ar-replaceBaseName (Path ar pcs (File pc)) bn =- Path ar pcs $ File $- addExtensionPC (PathComponent bn) $ snd $ splitExtensionPC pc--replaceDirectory :: FilePath ar1 -> DirPath ar2 -> FilePath ar2-replaceDirectory (Path _ _ fd) (Path ar pcs _) = Path ar pcs fd--replaceFileName :: FilePath ar -> String -> FilePath ar-replaceFileName (Path ar pcs _) fn = Path ar pcs (File (PathComponent fn))----- | Split on the extension. 'addExtension' is the inverse.------ >> uncurry (<.>) (Posix.splitExtension x) == x--- >> uncurry Posix.addExtension (Posix.splitExtension x) == x--- >> Posix.splitExtension (Posix.asRelFile "file.txt") == ("file",".txt")--- >> Posix.splitExtension (Posix.asRelFile "file") == ("file","")--- >> Posix.splitExtension (Posix.asRelFile "file/file.txt") == ("file/file",".txt")--- >> Posix.splitExtension (Posix.asRelFile "file.txt/boris") == ("file.txt/boris","")--- >> Posix.splitExtension (Posix.asRelFile "file.txt/boris.ext") == ("file.txt/boris",".ext")--- >> Posix.splitExtension (Posix.asRelFile "file/path.txt.bob.fred") == ("file/path.txt.bob",".fred")-splitExtension :: FilePath ar -> (FilePath ar, String)-splitExtension (Path ar pcs (File pc)) =- first (Path ar pcs . File) $ splitExtensionPC pc---- | Split on all extensions------ >> Posix.splitExtensions (Posix.asRelFile "file.tar.gz") == ("file",".tar.gz")-splitExtensions :: FilePath ar -> (FilePath ar, String)-splitExtensions (Path ar pcs (File pc)) =- first (Path ar pcs . File) $ splitExtensionsPC pc--prop_split_combineExt :: AbsFile -> Property-prop_split_combineExt p = property $ p == uncurry (<.>) (splitExtension p)--splitFileName :: FilePath ar -> (DirPath ar, RelFile)-splitFileName (Path ar pcs fd) = (Path ar pcs Dir, Path Rel [] fd)--prop_split_combine :: AbsFile -> Property-prop_split_combine p = property $ uncurry combine (splitFileName p) == p----- | Get the basename of a file------ >> Posix.takeBaseName (Posix.asAbsFile "/tmp/somedir/myfile.txt") == "myfile"--- >> Posix.takeBaseName (Posix.asRelFile "./myfile.txt") == "myfile"--- >> Posix.takeBaseName (Posix.asRelFile "myfile.txt") == "myfile"-takeBaseName :: FilePath ar -> RelFile-takeBaseName = takeFileName . dropExtension--takeDirectory :: FilePath ar -> DirPath ar-takeDirectory = fst . splitFileName---- | Get the extension of a file, returns @\"\"@ for no extension, @.ext@ otherwise.------ >> Posix.takeExtension x == snd (Posix.splitExtension x)--- >> Posix.takeExtension (Posix.addExtension x "ext") == ".ext"--- >> Posix.takeExtension (Posix.replaceExtension x "ext") == ".ext"-takeExtension :: FilePath ar -> String-takeExtension = snd . splitExtension---- | Get all extensions------ >> Posix.takeExtensions (Posix.asRelFile "file.tar.gz") == ".tar.gz"-takeExtensions :: FilePath ar -> String-takeExtensions = snd . splitExtensions---- | Get the filename component of a file path (ie stripping all parent dirs)------ >> Posix.takeFileName (Posix.asAbsFile "/tmp/somedir/myfile.txt") == "myfile.txt"--- >> Posix.takeFileName (Posix.asRelFile "./myfile.txt") == "myfile.txt"--- >> Posix.takeFileName (Posix.asRelFile "myfile.txt") == "myfile.txt"-takeFileName :: FilePath ar -> RelFile-takeFileName (Path _ _ fd) = Path Rel [] fd--prop_takeFileName_end :: AbsFile -> Property-prop_takeFileName_end p = property $ show (takeFileName p) `isSuffixOf` show p------------------------------------------------------------------------------ Auxillary Manipulation Functions---- | Check whether two strings are equal as file paths.------ >> Posix.equalFilePath "/tmp/" "/tmp"--- >> not $ Posix.equalFilePath "/tmp" "tmp"--- >> Windows.equalFilePath "file" "File"--- >> not $ Windows.equalFilePath "file" "dir"-equalFilePath :: String -> String -> Bool-equalFilePath s1 s2 =- let abs1 = isAbsoluteString s1- abs2 = isAbsoluteString s2- in abs1 == abs2 &&- if abs1- then asAbsDir s1 == asAbsDir s2- else asRelDir s1 == asRelDir s2---- | Constructs a 'RelPath' from a list of components.--- It is an unchecked error if the path components contain path separators.--- It is an unchecked error if a 'RelFile' path is empty.------ >> Posix.joinPath ["tmp","someDir","dir"] == Posix.asRelDir "tmp/someDir/dir"--- >> Posix.joinPath ["tmp","someDir","file.txt"] == Posix.asRelFile "tmp/someDir/file.txt"-joinPath :: (FileDirClass fd) => [String] -> RelPath fd-joinPath = mkPathFromComponents Rel . map PathComponent---- | Currently just transforms:------ >> Posix.normalise "/tmp/fred/./jim/./file" == Posix.asAbsFile "/tmp/fred/jim/file"-normalise :: Path ar fd -> Path ar fd-normalise (Path ar pcs fd) =- Path ar (filter (PathComponent currentDirComponent /=) pcs) fd---- | Deconstructs a path into its components.------ >> Posix.splitPath (Posix.asAbsDir "/tmp/someDir/mydir.dir") == (True, ["tmp","someDir","mydir.dir"], Nothing)--- >> Posix.splitPath (Posix.asAbsFile "/tmp/someDir/myfile.txt") == (True, ["tmp","someDir"], Just "myfile.txt")-splitPath ::- (AbsRelClass ar, FileDirClass fd) =>- Path ar fd -> (Bool, [RelDir], Maybe RelFile)-splitPath (Path ar pcs fd) =- (isAbsolutePlain ar,- map (\pc -> Path Rel [pc] Dir) pcs,- maybeFileDir fd)--isAbsolutePlain :: (AbsRelClass ar) => ar -> Bool-isAbsolutePlain = absRelPlain (const True) (const False)--maybeFileDir :: (FileDirClass fd) => fd -> Maybe RelFile-maybeFileDir = fileDirPlain (Just . Path Rel []) (\Dir -> Nothing)---- | This function can be used to construct a relative path by removing--- the supplied 'AbsDir' from the front. It is a runtime 'error' if the--- supplied 'AbsPath' doesn't start with the 'AbsDir'.------ >> Posix.makeRelative "/tmp/somedir" "/tmp/somedir/anotherdir/file.txt" == Posix.asRelFile "anotherdir/file.txt"--- >> Posix.makeRelative "/tmp/somedir" "/tmp/somedir/anotherdir/dir" == Posix.asRelDir "anotherdir/dir"--- >> Windows.makeRelative "c:\\tmp\\somedir" "c:\\Tmp\\SomeDir\\AnotherDir\\File.txt" == Windows.asRelFile "AnotherDir\\File.txt"--- >> Windows.makeRelative "c:\\tmp\\somedir" "c:\\tmp\\somedir\\anotherdir\\dir" == Windows.asRelDir "anotherdir\\dir"-makeRelative :: (FileDirClass fd) => AbsDir -> AbsPath fd -> RelPath fd-makeRelative relTo@(Path relToAR relToPCs Dir) orig@(Path origAR origPCs fd) =- maybe (error msg) (flip (Path Rel) fd) $- guard (relToAR == origAR) >> stripPrefix relToPCs origPCs- where- msg =- printf "System.Path can't make (%s) relative to (%s)"- (show orig) (show relTo)---- | Joins an absolute directory with a relative path to construct a--- new absolute path.------ >> Posix.makeAbsolute "/tmp" "file.txt" == Posix.asAbsFile "/tmp/file.txt"--- >> Posix.makeAbsolute "/tmp" "adir/file.txt" == Posix.asAbsFile "/tmp/adir/file.txt"--- >> Posix.makeAbsolute "/tmp" "adir/dir" == Posix.asAbsDir "/tmp/adir/dir"-makeAbsolute :: AbsDir -> RelPath fd -> AbsPath fd-makeAbsolute = genericMakeAbsolute---- | Converts a relative path into an absolute one by--- prepending the current working directory.-makeAbsoluteFromCwd :: RelPath fd -> IO (AbsPath fd)-makeAbsoluteFromCwd = genericMakeAbsoluteFromCwd---- | As for 'makeAbsolute', but for use when the path may already be--- absolute (in which case it is left unchanged).------ >> Posix.genericMakeAbsolute "/tmp" (Posix.asRelFile "file.txt") == "/tmp/file.txt"--- >> Posix.genericMakeAbsolute "/tmp" (Posix.asRelFile "adir/file.txt") == "/tmp/adir/file.txt"--- >> Posix.genericMakeAbsolute "/tmp" (Posix.asAbsFile "adir/file.txt") == "/adir/file.txt"--- >> Posix.genericMakeAbsolute "/tmp" (Posix.asAbsFile "/adir/file.txt") == "/adir/file.txt"-genericMakeAbsolute :: AbsRelClass ar => AbsDir -> Path ar fd -> AbsPath fd-genericMakeAbsolute base p = absRel id (base </>) p---- | As for 'makeAbsoluteFromCwd', but for use when the path may already be--- absolute (in which case it is left unchanged).-genericMakeAbsoluteFromCwd :: AbsRelClass ar => Path ar fd -> IO (AbsPath fd)-genericMakeAbsoluteFromCwd p = do- cwdString <- SD.getCurrentDirectory -- we don't use System.Path.Directory impl here to avoid module cycle- return $ genericMakeAbsolute (asAbsDir cwdString) p--prop_makeAbsoluteFromDir_endSame :: AbsDir -> RelFile -> Property-prop_makeAbsoluteFromDir_endSame base p =- property $ show p `isSuffixOf` show (makeAbsolute base p)--prop_makeAbsoluteFromDir_startSame :: AbsDir -> RelFile -> Property-prop_makeAbsoluteFromDir_startSame base p =- property $ show base `isPrefixOf` show (makeAbsolute base p)---- prop_makeAbsoluteFromDir_startSameAbs :: AbsDir -> AbsFile -> Property--- prop_makeAbsoluteFromDir_startSameAbs base p = property $ show base `isPrefixOf` show (makeAbsolute base p)------------------------------------------------------------------------------ NYI - Not Yet Implemented--{--splitSearchPath :: String -> [String]-getSearchPath :: IO [String]-splitDrive :: String -> (String, String)-joinDrive :: String -> String -> String-takeDrive :: String -> String-hasDrive :: String -> Bool-dropDrive :: String -> String-isDrive :: String -> Bool-isValid :: String -> Bool-makeValid :: String -> String--}------------------------------------------------------------------------------ Path Predicates---- | Test whether a @'Path' ar fd@ is absolute.------ >> Posix.isAbsolute (Posix.asAbsFile "fred")--- >> Posix.isAbsolute (Posix.asAbsFile "/fred")--- >> Windows.isAbsolute (Windows.asAbsFile "\\fred")--- >> Windows.isAbsolute (Windows.asAbsFile "c:\\fred")-isAbsolute :: AbsRelClass ar => Path ar fd -> Bool-isAbsolute = absRel (const True) (const False)---- | Test whether the 'String' would correspond to an absolute path--- if interpreted as a 'Path'.-isAbsoluteString :: String -> Bool-isAbsoluteString [] = False -- Treat the empty string as relative because it doesn't start with 'pathSeparators'-isAbsoluteString (x:xs) =- isPathSeparator x -- Absolute if first char is a path separator- ||- isWindows && isAlpha x && isPrefixOf ":" xs---- | Invariant - this should return True iff arg is of type @'Path' Rel _@------ > isRelative = not . isAbsolute--- >> Posix.isRelative (Posix.asRelFile "fred")--- >> Posix.isRelative (Posix.asRelFile "/fred")--- >> Windows.isRelative (Windows.asRelFile "fred")-isRelative :: AbsRelClass ar => Path ar fd -> Bool-isRelative = not . isAbsolute---- | Test whether the 'String' would correspond to a relative path--- if interpreted as a 'Path'.------ > isRelativeString = not . isAbsoluteString-isRelativeString :: String -> Bool-isRelativeString = not . isAbsoluteString----- | Does the given filename have an extension?------ >> null (Posix.takeExtension x) == not (Posix.hasAnExtension x)-hasAnExtension :: FilePath ar -> Bool-hasAnExtension = not . null . snd . splitExtension---- | Does the given filename have the given extension?------ >> Posix.hasExtension ".hs" (Posix.asRelFile "MyCode.hs")--- >> Posix.hasExtension ".hs" (Posix.asRelFile "MyCode.bak.hs")--- >> not $ Posix.hasExtension ".hs" (Posix.asRelFile "MyCode.hs.bak")-hasExtension :: String -> FilePath ar -> Bool-hasExtension ext = (==ext) . snd . splitExtension------------------------------------------------------------------------------ Separators---- | This is largely for 'System.FilePath' compatability-addTrailingPathSeparator :: String -> String-addTrailingPathSeparator = (++[pathSeparator])---- | This is largely for 'System.FilePath' compatability-dropTrailingPathSeparator :: String -> String-dropTrailingPathSeparator = init---- | File extension character------ >> Posix.extSeparator == '.'-extSeparator :: Char-extSeparator = '.'---- | This is largely for 'System.FilePath' compatability-hasTrailingPathSeparator :: String -> Bool-hasTrailingPathSeparator = isPathSeparator . last---- | The character that separates directories. In the case where more than--- one character is possible, 'pathSeparator' is the \'ideal\' one.------ >> Posix.isPathSeparator Posix.pathSeparator-pathSeparator :: Char-pathSeparator | isWindows = '\\'- | otherwise = '/'---- | The list of all possible separators.------ >> Posix.pathSeparator `elem` Posix.pathSeparators-pathSeparators :: [Char]-pathSeparators = return pathSeparator---- | The character that is used to separate the entries in the $PATH environment variable.----searchPathSeparator :: Char-searchPathSeparator = ':'---- | Is the character an extension character?------ >> Posix.isExtSeparator a == (a == Posix.extSeparator)-isExtSeparator :: Char -> Bool-isExtSeparator = (== extSeparator)---- | Rather than using @(== 'pathSeparator')@, use this. Test if something--- is a path separator.------ >> Posix.isPathSeparator a == (a `elem` Posix.pathSeparators)-isPathSeparator :: Char -> Bool-isPathSeparator = flip elem pathSeparators---- | Is the character a file separator?------ >> Posix.isSearchPathSeparator a == (a == Posix.searchPathSeparator)-isSearchPathSeparator :: Char -> Bool-isSearchPathSeparator = (== searchPathSeparator)------------------------------------------------------------------------------ Generic Manipulation Functions---- These functions support manipulation of extensions on directories--- as well as files. They have looser types than the corresponding--- 'Basic Manipulation Functions', but it is expected that the basic--- functions will be used more frequently as they provide more checks.---- | This is a more flexible variant of 'addExtension' / '<.>' which can--- work with files or directories------ >> Posix.genericAddExtension "/" "x" == Posix.asAbsDir "/.x"--- >> Posix.genericAddExtension "/a" "x" == Posix.asAbsDir "/a.x"--- >> Posix.genericAddExtension "" "x" == Posix.asRelFile ".x"--- >> Posix.genericAddExtension "" "" == Posix.asRelFile ""-genericAddExtension :: (FileDirClass fd) => Path ar fd -> String -> Path ar fd-genericAddExtension p "" = p-genericAddExtension path ext =- runAddExtension- (switchFileDir- (AddExtension $- \(Path ar pcs (File pc)) ->- Path ar pcs $ File $ addExtensionPC pc ext)- (AddExtension $- \(Path ar pcs0 Dir) ->- let pcs = if null pcs0 then [PathComponent ""] else pcs0- in Path ar (mapLast (flip addExtensionPC ext) pcs) Dir))- path--newtype- AddExtension ar fd =- AddExtension {runAddExtension :: Path ar fd -> Path ar fd}--genericDropExtension :: (FileDirClass fd) => Path ar fd -> Path ar fd-genericDropExtension = fst . genericSplitExtension--genericDropExtensions :: (FileDirClass fd) => Path ar fd -> Path ar fd-genericDropExtensions = fst . genericSplitExtensions--genericSplitExtension ::- (FileDirClass fd) => Path ar fd -> (Path ar fd, String)-genericSplitExtension =- runSplitExtension $- switchFileDir- (SplitExtension $- \(Path ar pcs (File pc)) ->- first (Path ar pcs . File) $ splitExtensionPC pc)- (SplitExtension $- \(Path ar pcs Dir) ->- first (flip (Path ar) Dir) $- mapLastPair- (error "genericSplitExtension: empty path")- splitExtensionPC pcs)--genericSplitExtensions ::- (FileDirClass fd) => Path ar fd -> (Path ar fd, String)-genericSplitExtensions =- runSplitExtension $- switchFileDir- (SplitExtension $- \(Path ar pcs (File pc)) ->- first (Path ar pcs . File) $ splitExtensionsPC pc)- (SplitExtension $- \(Path ar pcs Dir) ->- first (flip (Path ar) Dir) $- mapLastPair- (error "genericSplitExtensions: empty path")- splitExtensionsPC pcs)--genericTakeExtension :: (FileDirClass fd) => Path ar fd -> String-genericTakeExtension = snd . genericSplitExtension--genericTakeExtensions :: (FileDirClass fd) => Path ar fd -> String-genericTakeExtensions = snd . genericSplitExtension--newtype- SplitExtension ar fd =- SplitExtension {runSplitExtension :: Path ar fd -> (Path ar fd, String)}----- move to utility-ht-mapLast :: (a -> a) -> [a] -> [a]-mapLast f xs = zipWith id (drop 1 $ map (const id) xs ++ [f]) xs--mapLastPair :: b -> (a -> (a,b)) -> [a] -> ([a], b)-mapLastPair b0 f xs =- case reverse xs of- [] -> (xs, b0)- y:ys ->- let (a, b) = f y- in (reverse ys ++ [a], b)--addExtensionPC :: PathComponent -> String -> PathComponent-addExtensionPC p "" = p-addExtensionPC (PathComponent pc) ext =- PathComponent $ pc ++- if [extSeparator] `isPrefixOf` ext- then ext- else extSeparator : ext--splitExtensionPC :: PathComponent -> (PathComponent, String)-splitExtensionPC (PathComponent s) = (PathComponent s1, s2)- where (s1,s2) = fixTrailingDot $ rbreak isExtSeparator s- fixTrailingDot ("",r2) = (r2,"")- fixTrailingDot (r1,r2) | [extSeparator] `isSuffixOf` r1 = (init r1, extSeparator:r2)- | otherwise = (r1,r2)- swap (x,y) = (y,x)- rbreak q = (reverse *** reverse) . swap . break q . reverse--splitExtensionsPC :: PathComponent -> (PathComponent, String)-splitExtensionsPC (PathComponent s) =- first PathComponent $ break isExtSeparator s----------------------------------------------------------------------------- QuickCheck--_testall :: IO ()-_testall = do- putStrLn "Running QuickCheck tests..."- quickCheck prop_asPath_getPathString- quickCheck prop_mkPathFromComponents_pathComponents- quickCheck prop_makeAbsoluteFromDir_endSame- quickCheck prop_makeAbsoluteFromDir_startSame- quickCheck prop_split_combine- quickCheck prop_takeFileName_end- quickCheck prop_split_combineExt- putStrLn "Tests completed."---- test :: Testable a => a -> IO ()--- test = quickCheck--qcFileComponent :: Gen PathComponent-qcFileComponent = PathComponent <$> frequency [- (1, return "someFile"),- (1, return "fileWith.ext"),- (1, return "file.with.multiple.exts"),- (1, return "file with spcs")- ]--qcDirComponent :: Gen PathComponent-qcDirComponent = PathComponent <$> frequency [- (1, return "someDir"),- (1, return "aDir"),- (1, return "aFolder"),- (1, return "a folder"),- (1, return "directory")- ]--instance Arbitrary PathComponent where- arbitrary = oneof [qcFileComponent, qcDirComponent]---qcGenPath ::- (AbsRelClass ar, FileDirClass fd) =>- Gen PathComponent -> Gen (Path ar fd)-qcGenPath qcLastComponent = do- ar <- switchAbsRel (fmap (Abs . (:":")) $ QC.choose ('a', 'z')) (return Rel)- pcs <- QC.listOf qcDirComponent- pc <- qcLastComponent- return $ mkPathFromComponents ar (pcs ++ [pc])--qcFilePath :: (AbsRelClass ar) => Gen (FilePath ar)-qcFilePath = qcGenPath qcFileComponent--qcDirPath :: (AbsRelClass ar) => Gen (DirPath ar)-qcDirPath = qcGenPath qcDirComponent--qcPath :: (AbsRelClass ar, FileDirClass fd) => Gen (Path ar fd)-qcPath =- getFunctorPath $- switchFileDir (FunctorPath qcFilePath) (FunctorPath qcDirPath)--instance (AbsRelClass ar, FileDirClass fd) => Arbitrary (Path ar fd) where+module System.Path.Internal+(+ -- * The main filepath (& dirpath) abstract type+ Path, -- kept abstract++ -- * Possible types for Path type parameters+ Abs,+ Rel,+ AbsOrRel,+ File,+ Dir,+ FileOrDir,++ -- * Type Synonyms+ AbsFile,+ RelFile,+ AbsDir,+ RelDir,+ AbsOrRelFile,+ AbsOrRelDir,+ AbsFileOrDir,+ RelFileOrDir,+ AbsOrRelFileOrDir,++ AbsPath,+ RelPath,+ FilePath,+ DirPath,+ AbsOrRelPath,+ FileOrDirPath,++ -- * Classes+ AbsRelClass(..), AbsOrRelClass(..), absRel,+ FileOrDirClass(..), FileDirClass(..), fileDir,++ -- * Path to String conversion+ toString,+ getPathString,++ -- * Constants+ rootDir,+ currentDir,+ emptyFile,++ -- * Parsing Functions+ maybePath,+ parsePath,++ -- * Checked Construction Functions+ path,+ relFile,+ relDir,+ absFile,+ absDir,+ relPath,+ absPath,+ filePath,+ dirPath,++ idAbsOrRel, idAbs, idRel,+ idFileOrDir, idFile, idDir,++ -- * Unchecked Construction Functions+ asPath,+ asRelFile,+ asRelDir,+ asAbsFile,+ asAbsDir,+ asRelPath,+ asAbsPath,+ asFilePath,+ asDirPath,++ -- * Checked Construction Functions+ mkPathAbsOrRel,+ mkPathFileOrDir,+ mkAbsPath,+ mkAbsPathFromCwd,++ -- * Basic Manipulation Functions+ (</>),+ (<.>),+ (<++>),+ addExtension,+ combine,+ dropExtension,+ dropExtensions,+ dropFileName,+ replaceExtension,+ replaceBaseName,+ replaceDirectory,+ replaceFileName,+ splitExtension,+ splitExtensions,+ splitFileName,+ takeBaseName,+ takeDirectory,+ takeExtension,+ takeExtensions,+ takeFileName,+ mapFileName,++ -- * Auxillary Manipulation Functions+ equalFilePath,+ joinPath,+ normalise,+ splitPath,+ makeRelative,+ makeRelativeMaybe,+ makeAbsolute,+ makeAbsoluteFromCwd,+ dynamicMakeAbsolute,+ dynamicMakeAbsoluteFromCwd,+ genericMakeAbsolute,+ genericMakeAbsoluteFromCwd,+ pathMap,+ dirFromFile,+ fileFromDir,+ toFileOrDir,+ fromFileOrDir,+ fileFromFileOrDir,+ dirFromFileOrDir,++ -- * Path Predicates+ isAbsolute,+ isRelative,+ isAbsoluteString,+ isRelativeString,+ hasAnExtension,+ hasExtension,++ -- * Separators+ System(..),+ extSeparator,+ searchPathSeparator,+ isExtSeparator,+ isSearchPathSeparator,++ -- * Generic Manipulation Functions+ genericAddExtension,+ genericDropExtension,+ genericDropExtensions,+ genericSplitExtension,+ genericSplitExtensions,+ genericTakeExtension,+ genericTakeExtensions,++ -- * Tests+ testAll,+ isValid,+)++where++import qualified System.Directory as SD++import qualified Control.Monad.Trans.Class as MT+import qualified Control.Monad.Trans.State as MS+import Control.Monad (MonadPlus, guard, liftM2, mplus, mzero)+import Control.Applicative (Const(Const), liftA2, (<$>))+import Control.DeepSeq (NFData(rnf))++import qualified Data.Monoid.HT as MonHT+import qualified Data.List.HT as ListHT+import Data.Tagged (Tagged(Tagged), untag)+import Data.Functor.Compose (Compose(Compose), getCompose)+import Data.List (isSuffixOf, isPrefixOf, stripPrefix, intersperse)+import Data.String (IsString(fromString))+import Data.Maybe.HT (toMaybe)+import Data.Maybe (fromMaybe, maybeToList)+import Data.Tuple.HT (mapFst, mapSnd)+import Data.Monoid (Monoid(mempty, mappend, mconcat), Endo(Endo), appEndo)+import Data.Char (isSpace)+import Data.Ord.HT (comparing)+import Data.Eq.HT (equating)++import Text.Show.HT (concatS)+import Text.Printf (printf)++import qualified Test.QuickCheck as QC+import Test.QuickCheck+ (Gen, Property, property, Arbitrary(arbitrary), frequency)++import Prelude hiding (FilePath)+++------------------------------------------------------------------------+-- Types++newtype Abs = Abs GenComponent+data Rel = Rel+data AbsOrRel = AbsO GenComponent | RelO++absPC :: String -> Abs+absPC = Abs . PathComponent++newtype File = File GenComponent+data Dir = Dir+data FileOrDir = FileOrDir+++data Generic = Generic++_osDummy :: Generic+_osDummy = Generic+++-- | This is the main filepath abstract datatype+data Path os ar fd = Path ar [PathComponent os] fd++instance+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Eq (Path os ar fd) where+ (==) = equating inspectPath++instance+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Ord (Path os ar fd) where+ compare = comparing inspectPath++inspectPath ::+ Path os ar fd -> (WrapAbsRel os ar, [PathComponent os], WrapFileDir os fd)+inspectPath (Path ar pcs fd) = (WrapAbsRel ar, pcs, WrapFileDir fd)+++newtype WrapAbsRel os ar = WrapAbsRel {unwrapAbsRel :: ar}++instance (System os, AbsOrRelClass ar) => Eq (WrapAbsRel os ar) where+ (==) = equating inspectAbsRel++instance (System os, AbsOrRelClass ar) => Ord (WrapAbsRel os ar) where+ compare = comparing inspectAbsRel++inspectAbsRel ::+ (AbsOrRelClass ar) =>+ WrapAbsRel os ar -> Either (PathComponent os) ()+inspectAbsRel =+ absRelPlain (Left . PathComponent) (Right ()) . unwrapAbsRel+++newtype WrapFileDir os fd = WrapFileDir {unwrapFileDir :: fd}++instance (System os, FileOrDirClass fd) => Eq (WrapFileDir os fd) where+ (==) = equating inspectFileDir++instance (System os, FileOrDirClass fd) => Ord (WrapFileDir os fd) where+ compare = comparing inspectFileDir++inspectFileDir ::+ (FileOrDirClass ar) =>+ WrapFileDir os ar -> Either (PathComponent os) ()+inspectFileDir =+ fileOrDirPlain (Left . retagPC) (Right ()) (Right ()) . unwrapFileDir+++{- |+We cannot have a PathComponent without phantom types plus a Tagged wrapper,+because we need specialised Eq and Ord instances.+-}+type GenComponent = PathComponent Generic++newtype PathComponent os = PathComponent String++instance (System os) => Eq (PathComponent os) where+ (==) = equating (applyComp canonicalize)++instance (System os) => Ord (PathComponent os) where+ compare = comparing (applyComp canonicalize)++applyComp :: Tagged os (String -> String) -> PathComponent os -> String+applyComp (Tagged canon) (PathComponent pc) = canon pc++retagPC :: GenComponent -> PathComponent os+retagPC (PathComponent pc) = PathComponent pc++untagPC :: PathComponent os -> GenComponent+untagPC (PathComponent pc) = PathComponent pc++selTag :: Path os ar fd -> Tagged os a -> a+selTag _ = untag+++type AbsFile os = Path os Abs File+type RelFile os = Path os Rel File+type AbsDir os = Path os Abs Dir+type RelDir os = Path os Rel Dir+type AbsOrRelFile os = Path os AbsOrRel File+type AbsOrRelDir os = Path os AbsOrRel Dir+type AbsFileOrDir os = Path os Abs FileOrDir+type RelFileOrDir os = Path os Rel FileOrDir+type AbsOrRelFileOrDir os = Path os AbsOrRel FileOrDir++type AbsPath os fd = Path os Abs fd+type RelPath os fd = Path os Rel fd+type FilePath os ar = Path os ar File+type DirPath os ar = Path os ar Dir+type AbsOrRelPath os fd = Path os AbsOrRel fd+type FileOrDirPath os ar = Path os ar FileOrDir++instance NFData (PathComponent os) where+ rnf (PathComponent pc) = rnf pc++instance NFData Abs where+ rnf (Abs drive) = rnf drive++instance NFData Rel where+ rnf Rel = ()++instance NFData File where+ rnf (File pc) = rnf pc++instance NFData Dir where+ rnf Dir = ()++instance NFData FileOrDir where+ rnf FileOrDir = ()++instance (AbsOrRelClass ar, FileOrDirClass fd) => NFData (Path os ar fd) where+ rnf (Path ar pcs fd) =+ rnf (absRelPlain rnf () ar, pcs, fileOrDirPlain rnf () () fd)++absRelPlain :: (AbsOrRelClass ar) => (String -> a) -> a -> ar -> a+absRelPlain fAbs fRel =+ runFuncArg $+ switchAbsOrRel+ (FuncArg $ \(Abs (PathComponent drive)) -> fAbs drive)+ (FuncArg $ \Rel -> fRel)+ (FuncArg $ \ar ->+ case ar of+ AbsO (PathComponent drive) -> fAbs drive+ RelO -> fRel)++fileDirPlain :: (FileDirClass fd) => (GenComponent -> a) -> a -> fd -> a+fileDirPlain fFile fDir =+ runFuncArg $+ switchFileDir (FuncArg $ \(File pc) -> fFile pc) (FuncArg $ \Dir -> fDir)++fileOrDirPlain ::+ (FileOrDirClass fd) => (GenComponent -> a) -> a -> a -> fd -> a+fileOrDirPlain fFile fDir fFileOrDir =+ runFuncArg $+ switchFileOrDir (FuncArg $ \(File pc) -> fFile pc)+ (FuncArg $ \Dir -> fDir) (FuncArg $ \FileOrDir -> fFileOrDir)++newtype FuncArg b a = FuncArg {runFuncArg :: a -> b}++-- I don't think this basic type of fold is appropriate for a nested datatype+-- pathFold :: a -> (a -> String -> a) -> Path ar fd -> a+-- pathFold pr f PathRoot = pr+-- pathFold pr f (FileDir d pc) = f (pathFold pr f d) (unPathComponent pc)++-- | Map over the components of the path.+--+-- >> Path.pathMap (map toLower) (absDir "/tmp/Reports/SpreadSheets") == Posix.absDir "/tmp/reports/spreadsheets"+pathMap ::+ (FileOrDirClass fd) => (String -> String) -> Path os ar fd -> Path os ar fd+pathMap f (Path ar pcs fd) = Path ar (map (pcMap f) pcs) (fdMap f fd)++fdMap :: (FileOrDirClass fd) => (String -> String) -> fd -> fd+fdMap f = appEndo $ switchFileOrDir (Endo $ fileMap f) (Endo id) (Endo id)++fileMap :: (String -> String) -> File -> File+fileMap f (File pc) = File $ pcMap f pc++pcMap :: (String -> String) -> PathComponent os -> PathComponent os+pcMap f (PathComponent s) = PathComponent (f s)+++mapFilePart ::+ (GenComponent -> GenComponent) -> FilePath os ar -> FilePath os ar+mapFilePart f (Path ar pcs (File fd)) = Path ar pcs $ File $ f fd++splitFilePart ::+ (GenComponent -> (GenComponent, a)) -> FilePath os ar -> (FilePath os ar, a)+splitFilePart f (Path ar pcs (File fd)) = mapFst (Path ar pcs . File) $ f fd++mapPathDirs ::+ ([PathComponent os] -> [PathComponent os]) -> Path os ar fd -> Path os ar fd+mapPathDirs f ~(Path ar pcs fd) = Path ar (f pcs) fd+++------------------------------------------------------------------------+-- Type classes and machinery for switching on Abs/Rel and File/Dir++-- | This class provides a way to prevent other modules+-- from making further 'AbsRelClass' or 'FileDirClass'+-- instances+class Private p+instance Private Abs+instance Private Rel+instance Private AbsOrRel+instance Private File+instance Private Dir+instance Private FileOrDir++-- | This class allows selective behaviour for absolute and+-- relative paths and is mostly for internal use.+class Private ar => AbsOrRelClass ar where+ {- |+ See <https://wiki.haskell.org/Closed_world_instances>+ for the used technique.+ -}+ switchAbsOrRel :: f Abs -> f Rel -> f AbsOrRel -> f ar++instance AbsOrRelClass Abs where switchAbsOrRel f _ _ = f+instance AbsOrRelClass Rel where switchAbsOrRel _ f _ = f+instance AbsOrRelClass AbsOrRel where switchAbsOrRel _ _ f = f++class AbsOrRelClass ar => AbsRelClass ar where+ switchAbsRel :: f Abs -> f Rel -> f ar++instance AbsRelClass Abs where switchAbsRel f _ = f+instance AbsRelClass Rel where switchAbsRel _ f = f++absRel ::+ (AbsOrRelClass ar) =>+ (AbsPath os fd -> a) -> (RelPath os fd -> a) -> Path os ar fd -> a+absRel fAbs fRel (Path ar pcs fd) =+ absRelPlain+ (\drive -> fAbs $ Path (Abs (PathComponent drive)) pcs fd)+ (fRel $ Path Rel pcs fd)+ ar++class AbsRelClass ar => IsAbs ar where switchAbs :: f Abs -> f ar+instance IsAbs Abs where switchAbs = id++class AbsRelClass ar => IsRel ar where switchRel :: f Rel -> f ar+instance IsRel Rel where switchRel = id+++-- | This class allows selective behaviour for file and+-- directory paths and is mostly for internal use.+class Private fd => FileOrDirClass fd where+ switchFileOrDir :: f File -> f Dir -> f FileOrDir -> f fd++instance FileOrDirClass File where switchFileOrDir f _ _ = f+instance FileOrDirClass Dir where switchFileOrDir _ f _ = f+instance FileOrDirClass FileOrDir where switchFileOrDir _ _ f = f++switchFileOrDirPath ::+ (FileOrDirClass fd) =>+ f (FilePath os ar) -> f (DirPath os ar) -> f (FileOrDirPath os ar) ->+ f (Path os ar fd)+switchFileOrDirPath f d fd =+ getCompose $ switchFileOrDir (Compose f) (Compose d) (Compose fd)++class FileOrDirClass fd => FileDirClass fd where+ switchFileDir :: f File -> f Dir -> f fd++instance FileDirClass File where switchFileDir f _ = f+instance FileDirClass Dir where switchFileDir _ f = f++switchFileDirPath ::+ (FileDirClass fd) =>+ f (FilePath os ar) -> f (DirPath os ar) -> f (Path os ar fd)+switchFileDirPath f d =+ getCompose $ switchFileDir (Compose f) (Compose d)++fileDir ::+ (FileDirClass fd) =>+ (FilePath os ar -> a) -> (DirPath os ar -> a) -> Path os ar fd -> a+fileDir f g = runFuncArg $ switchFileDirPath (FuncArg f) (FuncArg g)++class FileDirClass fd => IsFile fd where switchFile :: f File -> f fd+instance IsFile File where switchFile = id++class FileDirClass fd => IsDir fd where switchDir :: f Dir -> f fd+instance IsDir Dir where switchDir = id+++-- | Currently not exported+_eitherFromAbsRel ::+ AbsOrRelClass ar => Path os ar fd -> Either (AbsPath os fd) (RelPath os fd)+_eitherFromAbsRel = absRel Left Right++-- | Currently not exported+_eitherFromFileDir ::+ FileDirClass fd => Path os ar fd -> Either (FilePath os ar) (DirPath os ar)+_eitherFromFileDir = fileDir Left Right++------------------------------------------------------------------------+-- Read & Show instances++{- |+We show and parse file path components+using the rather generic 'relPath' smart constructor+instead of 'relFile', 'relDir' and @relPath str :: FileOrDirPath ar@.+Otherwise handling of all cases of 'File', 'Dir' and 'FileOrDir' types+becomes pretty complicated.+-}+-- >> show (Posix.rootDir </> relDir "bla" </> relFile "blub") == "rootDir </> relPath \"bla\" </> relPath \"blub\""+-- >> show (Just (Posix.rootDir </> relDir "bla" </> relFile "blub")) == "Just (rootDir </> relPath \"bla\" </> relPath \"blub\")"+-- >> show (Posix.currentDir </> relDir "bla" </> relFile "blub") == "currentDir </> relPath \"bla\" </> relPath \"blub\""+-- >> show (Just (Posix.currentDir </> relDir "bla" </> relFile "blub")) == "Just (currentDir </> relPath \"bla\" </> relPath \"blub\")"+-- >> show (Windows.absDir "c:" </> relDir "bla" </> relFile "blub") == "absDir \"c:\" </> relPath \"bla\" </> relPath \"blub\""+-- >> show (Just (Windows.absDir "c:\\" </> relDir "bla" </> relFile "blub")) == "Just (absDir \"c:\\\\\" </> relPath \"bla\" </> relPath \"blub\")"+instance+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Show (Path os ar fd) where+ showsPrec = untag showsPrecTagged++showsPrecTagged ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Tagged os (Int -> Path os ar fd -> ShowS)+showsPrecTagged =+ flip fmap rootStringTagged $ \root d x ->+ case pathComponents x of+ (ar, pcs) ->+ showParen (d>5) $ concatS $+ intersperse+ (showChar ' ' . showString combineOperator . showChar ' ') $+ absRelPlain+ (\drive ->+ if drive == root+ then showString rootName+ else showsCons absDirName drive)+ (showString currentName)+ ar :+ map (\(PathComponent pc) -> showsCons relPathName pc) pcs++showsCons :: Show a => String -> a -> ShowS+showsCons name arg = showString name . showChar ' ' . showsPrec 11 arg++{- |+Currently it also parses AbsOrRel and FileOrDir paths,+although these cannot be composed with the accepted combinators.+-}+-- >> read "rootDir" == Posix.rootDir+-- >> read "rootDir" == Windows.rootDir+-- >> read "currentDir" == Posix.currentDir+-- >> read "currentDir" == Windows.currentDir+-- >> let path = Posix.rootDir </> relDir "bla" </> relFile "blub" in read (show path) == path+-- >> let path = Just (Posix.rootDir </> relDir "bla" </> relFile "blub") in read (show path) == path+-- >> let path = Posix.currentDir </> relDir "bla" </> relFile "blub" in read (show path) == path+-- >> let path = Just (Posix.currentDir </> relDir "bla" </> relFile "blub") in read (show path) == path+-- >> let path = Windows.rootDir </> relDir "bla" </> relFile "blub" in read (show path) == path+-- >> let path = Just (Windows.rootDir </> relDir "bla" </> relFile "blub") in read (show path) == path+-- >> let path = Windows.absDir "c:" </> relDir "bla" </> relFile "blub" in read (show path) == path+instance+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Read (Path os ar fd) where+ readsPrec d = readParen (d>5) $ untag readsPrecTagged++readsPrecTagged ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Tagged os (ReadS (Path os ar fd))+readsPrecTagged =+ flip fmap readsSplitDrive $ \readsSplDrv ->+ let go =+ handleMismatch+ (skipSpaces >> matchString combineOperator)+ (return [])+ (liftM2 (:) (fmap PathComponent $ readsCons relPathName) go)+ in MS.runStateT $ do+ skipSpaces+ MT.lift . maybeToList =<<+ liftM2 maybePathFromComponents readsSplDrv go++skipSpaces :: (Monad m) => MS.StateT String m ()+skipSpaces = MS.modify $ dropWhile isSpace++readsCons :: (Read a) => String -> MS.StateT String [] a+readsCons name = do+ skipSpaces+ matchString name+ MS.StateT $ readsPrec 11++handleMismatch ::+ MS.StateT s Maybe () ->+ MS.StateT s m a -> MS.StateT s m a -> MS.StateT s m a+handleMismatch act err success =+ MS.StateT $ \s0 ->+ case MS.execStateT act s0 of+ Nothing -> MS.runStateT err s0+ Just s1 -> MS.runStateT success s1++matchString :: (MonadPlus m) => String -> MS.StateT String m ()+matchString prefix =+ MS.StateT $ maybe mzero (return . (,) ()) . stripPrefix prefix++readsSplitDrive ::+ (System os, AbsOrRelClass ar) => Tagged os (MS.StateT String [] ar)+readsSplitDrive =+ flip fmap readsSplitDriveAbs $ \readsSplDrvAbs ->+ switchAbsOrRel+ readsSplDrvAbs+ readsSplitDriveRel+ (mplus+ (fmap (\(Abs drive) -> AbsO drive) readsSplDrvAbs)+ (fmap (\Rel -> RelO) readsSplitDriveRel))++readsSplitDriveAbs :: (System os) => Tagged os (MS.StateT String [] Abs)+readsSplitDriveAbs =+ flip fmap rootStringTagged $ \root ->+ fmap absPC $+ (matchString rootName >> return root)+ `mplus`+ readsCons absDirName++readsSplitDriveRel :: (MonadPlus m) => MS.StateT String m Rel+readsSplitDriveRel = matchString currentName >> return Rel+++-- | Synonym of 'getPathString' intended for qualified use.+toString ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) => Path os ar fd -> String+toString = getPathString++-- | Convert the 'Path' into a plain 'String' as required for OS calls.+getPathString ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) => Path os ar fd -> String+getPathString = flip getPathStringS ""++getPathStringS ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) => Path os ar fd -> ShowS+getPathStringS x =+ case pathComponents x of+ (ar, []) ->+ absRelPlain showString (showString currentDirComponent) ar+ (ar, pcs) ->+ concatS $+ absRelPlain (\drive -> (showString drive :)) id ar $+ intersperse (showChar (selTag x pathSeparator)) $+ map (\(PathComponent pc) -> showString pc) pcs++prop_asPath_getPathString :: (System os) => AbsFile os -> Property+prop_asPath_getPathString p = property $ p == asPath (getPathString p)+++------------------------------------------------------------------------+-- Constants++-- >> Posix.toString Path.rootDir == "/"+-- >> Windows.toString Path.rootDir == "\\"+rootDir :: (System os) => AbsDir os+rootDir = untag rootDirTagged++rootDirTagged :: (System os) => Tagged os (AbsDir os)+rootDirTagged = fmap (\root -> Path (absPC root) [] Dir) rootStringTagged++rootStringTagged :: (System os) => Tagged os String+rootStringTagged = fmap (\sep -> [sep]) pathSeparator++-- >> Posix.toString Path.currentDir == "."+-- >> Windows.toString Path.currentDir == "."+currentDir :: (System os) => RelDir os+currentDir = Path Rel [] Dir++{- |+This is a file with path @\"\"@.+You will not be able to create a file with this name.+We also forbid parsing @\"\"@ by 'relFile'.+You might only need this file path as intermediate step+when manipulating extensions of files like @\".bashrc\"@.+-}+emptyFile :: (System os) => RelFile os+emptyFile = Path Rel [] $ File emptyPC++emptyPC :: PathComponent os+emptyPC = PathComponent ""++rootName :: String+rootName = "rootDir"++currentName :: String+currentName = "currentDir"++currentDirComponent :: String+currentDirComponent = "."++absDirName :: String+absDirName = "absDir"++relPathName :: String+relPathName = "relPath"+++------------------------------------------------------------------------+-- Parsing Functions++-- | This function is intended for checking and parsing paths+-- provided as user input.+--+-- >> fmap Posix.toString (Posix.maybePath "/" :: Maybe Posix.AbsDir) == Just "/"+-- >> fmap Posix.toString (Posix.maybePath "/" :: Maybe Posix.AbsFile) == Nothing+-- >> fmap Posix.toString (Posix.maybePath "/" :: Maybe Posix.RelDir) == Nothing+-- >> fmap Posix.toString (Posix.maybePath "/" :: Maybe Posix.RelFile) == Nothing+-- >> fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.AbsDir) == Just "/tmp"+-- >> fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.AbsFile) == Just "/tmp"+-- >> fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.RelDir) == Nothing+-- >> fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.RelFile) == Nothing+-- >> fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.AbsDir) == Just "/tmp"+-- >> fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.AbsFile) == Nothing+-- >> fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.RelDir) == Nothing+-- >> fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.RelFile) == Nothing+-- >> fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.AbsOrRelFileOrDir) == Just "/tmp"+-- >> fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.AbsOrRelFileOrDir) == Just "/tmp"+-- >> fmap Posix.toString (Posix.maybePath "file.txt" :: Maybe Posix.RelFile) == Just "file.txt"+-- >> fmap Posix.toString (Posix.maybePath "file.txt" :: Maybe Posix.AbsFile) == Nothing+-- >> fmap Windows.toString (Windows.maybePath "\\tmp" :: Maybe Windows.AbsDir) == Just "\\tmp"+-- >> fmap Windows.toString (Windows.maybePath "a:\\tmp" :: Maybe Windows.AbsDir) == Just "a:\\tmp"+-- >> fmap Windows.toString (Windows.maybePath "a:tmp" :: Maybe Windows.AbsDir) == Just "a:tmp"+-- >> fmap Windows.toString (Windows.maybePath "a:\\" :: Maybe Windows.AbsDir) == Just "a:\\"+-- >> fmap Windows.toString (Windows.maybePath "a:" :: Maybe Windows.AbsDir) == Just "a:"+-- >> fmap Windows.toString (Windows.maybePath "tmp" :: Maybe Windows.RelDir) == Just "tmp"+-- >> fmap Windows.toString (Windows.maybePath "\\tmp" :: Maybe Windows.RelDir) == Nothing+-- >> fmap Windows.toString (Windows.maybePath "a:\\tmp" :: Maybe Windows.RelDir) == Nothing+-- >> fmap Windows.toString (Windows.maybePath "a:tmp" :: Maybe Windows.RelDir) == Nothing+-- >> fmap Windows.toString (Windows.maybePath "tmp" :: Maybe Windows.AbsDir) == Nothing+maybePath ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ String -> Maybe (Path os ar fd)+maybePath str = do+ let (ar0, pcs0, fd0) = untag makePathComponents str+ ar <-+ case ar0 of+ AbsO pc -> switchAbsOrRel (Just $ Abs pc) Nothing (Just ar0)+ RelO -> switchAbsOrRel Nothing (Just Rel) (Just ar0)+ (pcs, fd) <-+ case fd0 of+ Left FileOrDir -> arrangeComponents pcs0+ Right Dir ->+ fmap ((,) pcs0) $+ switchFileOrDir Nothing (Just Dir) (Just FileOrDir)+ return $ Path ar pcs fd++parsePath ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ String -> Either String (Path os ar fd)+parsePath = pathWithNames arName fdName++pathWithNames ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Const String ar -> Const String fd ->+ String -> Either String (Path os ar fd)+pathWithNames (Const ar) (Const fd) str =+ maybe (Left (printf "\"%s\" is not a valid %s%spath" str ar fd)) Right $+ maybePath str++arName :: (AbsOrRelClass ar) => Const String ar+arName = switchAbsOrRel (Const "absolute ") (Const "relative ") (Const "")++fdName :: (FileOrDirClass fd) => Const String fd+fdName = switchFileOrDir (Const "file ") (Const "directory ") (Const "")++------------------------------------------------------------------------+-- Checked Construction Functions++-- | This function is intended for converting path strings+-- with known content, e.g. string literals, to the 'Path' type.+path ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ String -> Path os ar fd+path = either error id . parsePath++-- | Construct a 'RelFile' from a 'String'.+--+-- >> Posix.toString (Posix.relFile "file.txt") == "file.txt"+-- >> Posix.toString (Posix.relFile "tmp") == "tmp"+relFile :: (System os) => String -> RelFile os+relFile = path++-- | Construct a 'RelDir' from a 'String'.+--+-- >> Posix.toString (Posix.relDir ".") == "."+-- >> Posix.toString (Posix.relDir "file.txt") == "file.txt"+-- >> Posix.toString (Posix.relDir "tmp") == "tmp"+relDir :: (System os) => String -> RelDir os+relDir = path++-- | Construct an 'AbsFile' from a 'String'.+--+-- >> Posix.toString (Posix.absFile "/file.txt") == "/file.txt"+-- >> Posix.toString (Posix.absFile "/tmp") == "/tmp"+absFile :: (System os) => String -> AbsFile os+absFile = path++-- | Construct an 'AbsDir' from a 'String'.+--+-- >> Posix.toString (Posix.absDir "/file.txt") == "/file.txt"+-- >> Posix.toString (Posix.absDir "/tmp") == "/tmp"+absDir :: (System os) => String -> AbsDir os+absDir = path++-- | Construct a 'RelPath fd' from a 'String'.+relPath :: (System os, FileOrDirClass fd) => String -> RelPath os fd+relPath = path++-- | Construct an 'AbsPath fd' from a 'String'.+absPath :: (System os, FileOrDirClass fd) => String -> AbsPath os fd+absPath = path++-- | Construct a 'FilePath ar' from a 'String'.+filePath :: (System os, AbsOrRelClass ar) => String -> FilePath os ar+filePath = path++-- | Construct a 'DirPath ar' from a 'String'.+dirPath :: (System os, AbsOrRelClass ar) => String -> DirPath os ar+dirPath = path++++idAbsOrRel :: AbsOrRelPath os fd -> AbsOrRelPath os fd+idAbsOrRel = id++idAbs :: AbsPath os fd -> AbsPath os fd+idAbs = id++idRel :: RelPath os fd -> RelPath os fd+idRel = id+++idFileOrDir :: FileOrDirPath os fd -> FileOrDirPath os fd+idFileOrDir = id++idFile :: FilePath os fd -> FilePath os fd+idFile = id++idDir :: DirPath os fd -> DirPath os fd+idDir = id+++{-# DEPRECATED asPath "Use 'maybePath', 'parsePath' or 'path' instead." #-}+{-# DEPRECATED asRelFile "Use 'relFile' instead." #-}+{-# DEPRECATED asRelDir "Use 'relDir' instead." #-}+{-# DEPRECATED asAbsFile "Use 'absFile' instead." #-}+{-# DEPRECATED asAbsDir "Use 'absDir' instead." #-}+{-# DEPRECATED asRelPath "Use 'relPath' instead." #-}+{-# DEPRECATED asAbsPath "Use 'absPath' instead." #-}+{-# DEPRECATED asFilePath "Use 'filePath' instead." #-}+{-# DEPRECATED asDirPath "Use 'dirPath' instead." #-}++------------------------------------------------------------------------+-- Unchecked Construction Functions+-- NB - these construction functions are non-IO and do no checking!!++-- | Use a 'String' as a 'Path' whose type is determined by its context.+-- You should not use this and other @as*@ functions,+-- since they may silently turn a relative path to an absolute one,+-- or vice versa, or they may accept a path as file path+-- although it ends on a slash.+-- If you are certain about the string content+-- then you should use 'path'.+-- If you got the string as user input then use 'maybePath' or 'parsePath'.+--+-- >> Posix.asPath "/tmp" == Posix.absDir "/tmp"+-- >> Posix.asPath "file.txt" == Posix.relFile "file.txt"+-- >> Path.isAbsolute (Posix.asAbsDir "/tmp")+-- >> Path.isRelative (Posix.asRelDir "/tmp")+-- >> Posix.toString (Posix.asPath "/tmp" :: Posix.AbsDir) == "/tmp"+-- >> Posix.toString (Posix.asPath "/tmp" :: Posix.RelDir) == "tmp"+-- >> Windows.toString (Windows.asPath "\\tmp" :: Windows.AbsDir) == "\\tmp"+-- >> Windows.toString (Windows.asPath "a:\\tmp" :: Windows.AbsDir) == "a:\\tmp"+-- >> Windows.toString (Windows.asPath "a:tmp" :: Windows.AbsDir) == "a:tmp"+-- >> Windows.toString (Windows.asPath "tmp" :: Windows.RelDir) == "tmp"+asPath ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) => String -> Path os ar fd+asPath = uncurry mkPathFromComponents . untag mkPathComponents+++-- | Use a 'String' as a 'RelFile'. No checking is done.+--+-- >> Posix.toString (Posix.asRelFile "file.txt") == "file.txt"+-- >> Posix.toString (Posix.asRelFile "/file.txt") == "file.txt"+-- >> Posix.toString (Posix.asRelFile "tmp") == "tmp"+-- >> Posix.toString (Posix.asRelFile "/tmp") == "tmp"+asRelFile :: (System os) => String -> RelFile os+asRelFile = asPath++-- | Use a 'String' as a 'RelDir'. No checking is done.+--+-- >> Posix.toString (Posix.asRelDir ".") == "."+-- >> Posix.toString (Posix.asRelDir "file.txt") == "file.txt"+-- >> Posix.toString (Posix.asRelDir "/file.txt") == "file.txt"+-- >> Posix.toString (Posix.asRelDir "tmp") == "tmp"+-- >> Posix.toString (Posix.asRelDir "/tmp") == "tmp"+asRelDir :: (System os) => String -> RelDir os+asRelDir = asPath++-- | Use a 'String' as an 'AbsFile'. No checking is done.+--+-- >> Posix.toString (Posix.asAbsFile "/file.txt") == "/file.txt"+-- >> Posix.toString (Posix.asAbsFile "/tmp") == "/tmp"+asAbsFile :: (System os) => String -> AbsFile os+asAbsFile = asPath++-- | Use a 'String' as an 'AbsDir'. No checking is done.+--+-- >> Posix.toString (Posix.asAbsDir "/file.txt") == "/file.txt"+-- >> Posix.toString (Posix.asAbsDir "/tmp") == "/tmp"+asAbsDir :: (System os) => String -> AbsDir os+asAbsDir = asPath++-- | Use a 'String' as a 'RelPath fd'. No checking is done.+asRelPath :: (System os, FileOrDirClass fd) => String -> RelPath os fd+asRelPath = asPath++-- | Use a 'String' as an 'AbsPath fd'. No checking is done.+asAbsPath :: (System os, FileOrDirClass fd) => String -> AbsPath os fd+asAbsPath = asPath++-- | Use a 'String' as a 'FilePath ar'. No checking is done.+asFilePath :: (System os, AbsOrRelClass ar) => String -> FilePath os ar+asFilePath = asPath++-- | Use a 'String' as a 'DirPath ar'. No checking is done.+asDirPath :: (System os, AbsOrRelClass ar) => String -> DirPath os ar+asDirPath = asPath++-- | Forbid use of OverloadedStrings and prevent custom orphan instances+instance+ (ForbiddenSystem os, ForbiddenAbsRel ar, ForbiddenFileDir fd) =>+ IsString (Path os ar fd) where fromString = forbiddenFromString++class System os => ForbiddenSystem os where+ forbiddenFromString :: String -> Path os ar fd++class AbsRelClass ar => ForbiddenAbsRel ar where+class FileDirClass fd => ForbiddenFileDir fd where++------------------------------------------------------------------------+-- Checked Construction Functions++-- | Examines the supplied string and constructs an absolute or+-- relative path as appropriate.+--+-- >> Path.mkPathAbsOrRel "/tmp" == Left (Posix.absDir "/tmp")+-- >> Path.mkPathAbsOrRel "tmp" == Right (Posix.relDir "tmp")+-- >> Path.mkPathAbsOrRel "\\tmp" == Left (Windows.absDir "\\tmp")+-- >> Path.mkPathAbsOrRel "d:\\tmp" == Left (Windows.absDir "d:\\tmp")+-- >> Path.mkPathAbsOrRel "d:tmp" == Left (Windows.absDir "d:tmp")+-- >> Path.mkPathAbsOrRel "tmp" == Right (Windows.relDir "tmp")+mkPathAbsOrRel ::+ (System os, FileOrDirClass fd) =>+ String -> Either (AbsPath os fd) (RelPath os fd)+mkPathAbsOrRel = eitherAbsOrRel . asPath++eitherAbsOrRel :: AbsOrRelPath os fd -> Either (AbsPath os fd) (RelPath os fd)+eitherAbsOrRel (Path ar pcs fd) =+ case ar of+ AbsO drive -> Left $ Path (Abs drive) pcs fd+ RelO -> Right $ Path Rel pcs fd++-- | Searches for a file or directory with the supplied path string+-- and returns a 'File' or 'Dir' path as appropriate. If neither exists+-- at the supplied path, 'Nothing' is returned.+mkPathFileOrDir ::+ (System os, AbsOrRelClass ar) =>+ String -> IO (Maybe (Either (FilePath os ar) (DirPath os ar)))+mkPathFileOrDir s = do+ isfile <- SD.doesFileExist s+ isdir <- SD.doesDirectoryExist s+ case (isfile, isdir) of+ (False, False) -> return Nothing+ (True, False) -> return $ Just $ Left $ asPath s+ (False, True ) -> return $ Just $ Right $ asPath s+ (True, True ) -> ioError $ userError "mkPathFileOrDir - object type changed while checking"++-- | Convert a 'String' into an 'AbsPath' by interpreting it as+-- relative to the supplied directory if necessary.+--+-- >> Path.mkAbsPath (absDir "/tmp") "foo.txt" == Posix.absFile "/tmp/foo.txt"+-- >> Path.mkAbsPath (absDir "/tmp") "/etc/foo.txt" == Posix.absFile "/etc/foo.txt"+mkAbsPath ::+ (System os, FileOrDirClass fd) => AbsDir os -> String -> AbsPath os fd+mkAbsPath d = either id (makeAbsolute d) . mkPathAbsOrRel++-- | Convert a 'String' into an 'AbsPath' by interpreting it as+-- relative to the cwd if necessary.+mkAbsPathFromCwd ::+ (System os, FileOrDirClass fd) => String -> IO (AbsPath os fd)+mkAbsPathFromCwd = either return makeAbsoluteFromCwd . mkPathAbsOrRel+++------------------------------------------------------------------------+-- Internal Functions for GenComponent manipulation++mkPathFromComponents ::+ (FileOrDirClass fd) => ar -> [PathComponent os] -> Path os ar fd+mkPathFromComponents ar pcs =+ uncurry (Path ar) $+ switchFileOrDir+ (mapSnd File $+ ListHT.switchR ([], emptyPC) (curry $ mapSnd untagPC) pcs)+ (pcs, Dir)+ (pcs, FileOrDir)++maybePathFromComponents ::+ (FileOrDirClass fd) => ar -> [PathComponent os] -> Maybe (Path os ar fd)+maybePathFromComponents ar pcs =+ fmap (uncurry $ Path ar) $ arrangeComponents pcs++arrangeComponents ::+ (FileOrDirClass fd) => [PathComponent os] -> Maybe ([PathComponent os], fd)+arrangeComponents pcs =+ getCompose $+ switchFileOrDir+ (Compose $ fmap (mapSnd (File . untagPC)) $ ListHT.viewR pcs)+ (Compose $ Just (pcs, Dir))+ (Compose $ Just (pcs, FileOrDir))++mkPathComponents ::+ (System os, AbsOrRelClass ar) =>+ Tagged os (String -> (ar, [PathComponent os]))+mkPathComponents =+ liftA2+ (\isSep splDriveOS ->+ mapSnd (nonEmptyComponents . ListHT.chop isSep)+ . MS.runState splDriveOS)+ isPathSeparator splitDriveOS++{- |+Parse path string independent from expectations+expressed by the type parameters.+-}+makePathComponents ::+ (System os) =>+ Tagged os (String -> (AbsOrRel, [PathComponent os], Either FileOrDir Dir))+makePathComponents =+ liftA2+ (\isSep splAbsolute str ->+ let (ar, pct) =+ mapSnd (ListHT.chop isSep) $+ MS.runState splAbsolute str+ (pcs1, fd) =+ case ListHT.viewR pct of+ Nothing -> ([], Right Dir)+ Just (pcs, pc) ->+ if null pc -- caused by trailing slash+ then (pcs, Right Dir)+ else (pct, Left FileOrDir)+ in (ar, nonEmptyComponents pcs1, fd))+ isPathSeparator splitAbsoluteO++nonEmptyComponents :: [String] -> [PathComponent os]+nonEmptyComponents = map PathComponent . filter (not . null)++splitDriveOS ::+ (System os, AbsOrRelClass ar) => Tagged os (MS.State String ar)+splitDriveOS =+ liftA2+ (\splDrive splAbsolute ->+ switchAbsOrRel (fmap absPC splDrive) (return Rel) splAbsolute)+ splitDriveAbs splitAbsoluteO++splitDriveAbs :: (System os) => Tagged os (MS.State String String)+splitDriveAbs =+ liftA2+ (\isSep splDrive -> do+ drive <- splDrive+ xt <- MS.get+ case xt of+ [] -> return drive+ x:xs ->+ if isSep x+ then MS.put xs >> return (drive++[x])+ else return drive)+ isPathSeparator splitDrive++splitAbsoluteO :: (System os) => Tagged os (MS.State String AbsOrRel)+splitAbsoluteO =+ fmap (\drive -> if null drive then RelO else AbsO $ PathComponent drive)+ <$>+ splitAbsolute++pathComponents ::+ (FileOrDirClass fd) => Path os ar fd -> (ar, [PathComponent os])+pathComponents (Path ar pcs fd) =+ (ar, pcs ++ fileOrDirPlain ((:[]) . retagPC) [] [] fd)++prop_mkPathFromComponents_pathComponents :: (System os) => AbsDir os -> Property+prop_mkPathFromComponents_pathComponents p =+ property $ uncurry mkPathFromComponents (pathComponents p) == p++++------------------------------------------------------------------------+-- Basic Manipulation Functions++combineOperator :: String+combineOperator = "</>"+++instance (IsRel ar, IsDir fd) => Monoid (Path os ar fd) where+ mempty = Path relVar [] dirVar+ mappend (Path rel pcs0 _dir) (Path _rel pcs1 dir) =+ Path rel (pcs0 ++ pcs1) dir+ mconcat paths =+ Path relVar (concatMap (\(Path _rel pcs _dir) -> pcs) paths) dirVar++relVar :: IsRel ar => ar+relVar = unwrapAbsRel $ switchRel $ WrapAbsRel Rel++dirVar :: IsDir fd => fd+dirVar = unwrapFileDir $ switchDir $ WrapFileDir Dir+++-- | Infix variant of 'combine'.+--+-- >> Posix.toString (Posix.absDir "/tmp" </> Posix.relFile "file.txt") == "/tmp/file.txt"+-- >> Posix.toString (Posix.absDir "/tmp" </> Posix.relDir "dir" </> Posix.relFile "file.txt") == "/tmp/dir/file.txt"+-- >> Posix.toString (Posix.relDir "dir" </> Posix.relFile "file.txt") == "dir/file.txt"+-- >> Windows.toString (Windows.absDir "\\tmp" </> Windows.relFile "file.txt") == "\\tmp\\file.txt"+-- >> Windows.toString (Windows.absDir "c:\\tmp" </> Windows.relFile "file.txt") == "c:\\tmp\\file.txt"+-- >> Windows.toString (Windows.absDir "c:tmp" </> Windows.relFile "file.txt") == "c:tmp\\file.txt"+-- >> Windows.toString (Windows.absDir "c:\\" </> Windows.relDir "tmp" </> Windows.relFile "file.txt") == "c:\\tmp\\file.txt"+-- >> Windows.toString (Windows.absDir "c:" </> Windows.relDir "tmp" </> Windows.relFile "file.txt") == "c:tmp\\file.txt"+-- >> Windows.toString (Windows.relDir "dir" </> Windows.relFile "file.txt") == "dir\\file.txt"+(</>) :: DirPath os ar -> RelPath os fd -> Path os ar fd+Path ar pcs0 Dir </> Path Rel pcs1 fd = Path ar (pcs0 ++ pcs1) fd++infixr 5 </>++-- | Infix variant of 'addExtension'.+-- We only allow files (and not directories) to have extensions added+-- by this function. This is because it's the vastly common case and+-- an attempt to add one to a directory will - more often than not -+-- represent an error.+-- We don't however want to prevent the corresponding operation on+-- directories, and so we provide a function that is more flexible:+-- 'genericAddExtension'.+(<.>) :: FilePath os ar -> String -> FilePath os ar+p <.> ext = mapFilePart (flip addExtensionPC ext) p++infixl 7 <.>++(<++>) :: FilePath os ar -> String -> FilePath os ar+p <++> str = mapFileName (++str) p++infixl 7 <++>++-- | Add an extension, even if there is already one there.+-- E.g. @addExtension \"foo.txt\" \"bat\" -> \"foo.txt.bat\"@.+--+-- >> Path.addExtension (relFile "file.txt") "bib" == Posix.relFile "file.txt.bib"+-- >> Path.addExtension (relFile "file.") ".bib" == Posix.relFile "file..bib"+-- >> Path.addExtension (relFile "file") ".bib" == Posix.relFile "file.bib"+-- >> Path.addExtension Path.emptyFile "bib" == Posix.relFile ".bib"+-- >> Path.addExtension Path.emptyFile ".bib" == Posix.relFile ".bib"+-- >> Path.takeFileName (Path.addExtension Path.emptyFile "ext") == Posix.relFile ".ext"+addExtension :: FilePath os ar -> String -> FilePath os ar+addExtension = (<.>)++-- | Join an (absolute or relative) directory path with a relative+-- (file or directory) path to form a new path.+combine :: DirPath os ar -> RelPath os fd -> Path os ar fd+combine = (</>)++prop_combine_currentDir :: (System os) => RelDir os -> Property+prop_combine_currentDir p = property $ combine currentDir p == p+++-- | Remove last extension, and the \".\" preceding it.+--+-- >> Path.dropExtension x == fst (Path.splitExtension x)+dropExtension :: FilePath os ar -> FilePath os ar+dropExtension = fst . splitExtension++-- | Drop all extensions+--+-- >> not $ Path.hasAnExtension (Path.dropExtensions x)+dropExtensions :: FilePath os ar -> FilePath os ar+dropExtensions = fst . splitExtensions++-- | Synonym for 'takeDirectory'+dropFileName :: FilePath os ar -> DirPath os ar+dropFileName = fst . splitFileName+++-- | Set the extension of a file, overwriting one if already present.+--+-- >> Path.replaceExtension (relFile "file.txt") ".bob" == Posix.relFile "file.bob"+-- >> Path.replaceExtension (relFile "file.txt") "bob" == Posix.relFile "file.bob"+-- >> Path.replaceExtension (relFile "file") ".bob" == Posix.relFile "file.bob"+-- >> Path.replaceExtension (relFile "file.txt") "" == Posix.relFile "file"+-- >> Path.replaceExtension (relFile "file.fred.bob") "txt" == Posix.relFile "file.fred.txt"+replaceExtension :: FilePath os ar -> String -> FilePath os ar+replaceExtension p ext = dropExtension p <.> ext++replaceBaseName :: FilePath os ar -> String -> FilePath os ar+replaceBaseName p bn =+ mapFilePart (addExtensionPC (PathComponent bn) . snd . splitExtensionPC) p++replaceDirectory :: FilePath os ar1 -> DirPath os ar2 -> FilePath os ar2+replaceDirectory (Path _ _ fd) (Path ar pcs _) = Path ar pcs fd++replaceFileName :: FilePath os ar -> String -> FilePath os ar+replaceFileName p fn = mapFilePart (const (PathComponent fn)) p+++-- | Split on the extension. 'addExtension' is the inverse.+--+-- >> uncurry (<.>) (Path.splitExtension x) == x+-- >> uncurry Path.addExtension (Path.splitExtension x) == x+-- >> Path.splitExtension (relFile "file.txt") == (Posix.relFile "file",".txt")+-- >> Path.splitExtension (relFile ".bashrc") == (Posix.emptyFile, ".bashrc")+-- >> Path.splitExtension (relFile "file") == (Posix.relFile "file","")+-- >> Path.splitExtension (relFile "file/file.txt") == (Posix.relFile "file/file",".txt")+-- >> Path.splitExtension (relFile "file.txt/boris") == (Posix.relFile "file.txt/boris","")+-- >> Path.splitExtension (relFile "file.txt/boris.ext") == (Posix.relFile "file.txt/boris",".ext")+-- >> Path.splitExtension (relFile "file/path.txt.bob.fred") == (Posix.relFile "file/path.txt.bob",".fred")+splitExtension :: FilePath os ar -> (FilePath os ar, String)+splitExtension = splitFilePart splitExtensionPC++-- | Split on all extensions+--+-- >> Path.splitExtensions (relFile "file.tar.gz") == (Posix.relFile "file",".tar.gz")+splitExtensions :: FilePath os ar -> (FilePath os ar, String)+splitExtensions = splitFilePart splitExtensionsPC++prop_split_combineExt :: (System os) => AbsFile os -> Property+prop_split_combineExt p = property $ p == uncurry (<.>) (splitExtension p)++splitFileName :: FilePath os ar -> (DirPath os ar, RelFile os)+splitFileName (Path ar pcs fd) = (Path ar pcs Dir, Path Rel [] fd)++prop_split_combine :: (System os) => AbsFile os -> Property+prop_split_combine p = property $ uncurry combine (splitFileName p) == p+++-- | Get the basename of a file+--+-- >> Path.takeBaseName (absFile "/tmp/somedir/myfile.txt") == Posix.relFile "myfile"+-- >> Path.takeBaseName (relFile "./myfile.txt") == Posix.relFile "myfile"+-- >> Path.takeBaseName (relFile "myfile.txt") == Posix.relFile "myfile"+takeBaseName :: FilePath os ar -> RelFile os+takeBaseName = takeFileName . dropExtension++takeDirectory :: FilePath os ar -> DirPath os ar+takeDirectory = fst . splitFileName++-- | Get the extension of a file, returns @\"\"@ for no extension, @.ext@ otherwise.+--+-- >> Path.takeExtension x == snd (Path.splitExtension x)+-- >> Path.takeExtension (Path.addExtension x "ext") == ".ext"+-- >> Path.takeExtension (Path.replaceExtension x "ext") == ".ext"+takeExtension :: FilePath os ar -> String+takeExtension = snd . splitExtension++-- | Get all extensions+--+-- >> Path.takeExtensions (Posix.relFile "file.tar.gz") == ".tar.gz"+takeExtensions :: FilePath os ar -> String+takeExtensions = snd . splitExtensions++-- | Get the filename component of a file path (ie stripping all parent dirs)+--+-- >> Path.takeFileName (absFile "/tmp/somedir/myfile.txt") == Posix.relFile "myfile.txt"+-- >> Path.takeFileName (relFile "./myfile.txt") == Posix.relFile "myfile.txt"+-- >> Path.takeFileName (relFile "myfile.txt") == Posix.relFile "myfile.txt"+takeFileName :: FilePath os ar -> RelFile os+takeFileName (Path _ _ fd) = Path Rel [] fd++prop_takeFileName_end :: (System os) => AbsFile os -> Property+prop_takeFileName_end p =+ property $ getPathString (takeFileName p) `isSuffixOf` getPathString p++mapFileName :: (String -> String) -> FilePath os ar -> FilePath os ar+mapFileName = mapFilePart . pcMap+++------------------------------------------------------------------------+-- Auxillary Manipulation Functions++-- | Check whether two strings are equal as file paths.+--+-- >> Posix.equalFilePath "abc/def" "abc/def"+-- >> Posix.equalFilePath "abc/def" "abc//def"+-- >> Posix.equalFilePath "/tmp/" "/tmp"+-- >> Posix.equalFilePath "/tmp" "//tmp"+-- >> Posix.equalFilePath "/tmp" "///tmp"+-- >> not $ Posix.equalFilePath "abc" "def"+-- >> not $ Posix.equalFilePath "/tmp" "tmp"+-- >> Windows.equalFilePath "abc\\def" "abc\\def"+-- >> Windows.equalFilePath "abc\\def" "abc\\\\def"+-- >> Windows.equalFilePath "file" "File"+-- >> Windows.equalFilePath "\\file" "\\\\file"+-- >> Windows.equalFilePath "\\file" "\\\\\\file"+-- >> not $ Windows.equalFilePath "abc" "def"+-- >> not $ Windows.equalFilePath "file" "dir"+equalFilePath :: (System os) => Tagged os (String -> String -> Bool)+equalFilePath = equating <$> mkPathAbsOrRelTagged++mkPathAbsOrRelTagged ::+ (System os) =>+ Tagged os (String -> Either (AbsFileOrDir os) (RelFileOrDir os))+mkPathAbsOrRelTagged = Tagged mkPathAbsOrRel++-- | Constructs a 'RelPath' from a list of components.+-- It is an unchecked error if the path components contain path separators.+-- It is an unchecked error if a 'RelFile' path is empty.+--+-- >> Path.joinPath ["tmp","someDir","dir"] == Posix.relDir "tmp/someDir/dir"+-- >> Path.joinPath ["tmp","someDir","file.txt"] == Posix.relFile "tmp/someDir/file.txt"+joinPath :: (FileOrDirClass fd) => [String] -> RelPath os fd+joinPath = mkPathFromComponents Rel . map PathComponent++-- | Currently just transforms:+--+-- >> Path.normalise (absFile "/tmp/fred/./jim/./file") == Posix.absFile "/tmp/fred/jim/file"+normalise :: (System os) => Path os ar fd -> Path os ar fd+normalise = mapPathDirs (filter (PathComponent currentDirComponent /=))++-- | Deconstructs a path into its components.+--+-- >> Path.splitPath (Posix.absDir "/tmp/someDir/mydir.dir") == (True, map relDir ["tmp","someDir","mydir.dir"], Nothing)+-- >> Path.splitPath (Posix.absFile "/tmp/someDir/myfile.txt") == (True, map relDir ["tmp","someDir"], Just $ relFile "myfile.txt")+splitPath ::+ (AbsOrRelClass ar, FileDirClass fd) =>+ Path os ar fd -> (Bool, [RelDir os], Maybe (RelFile os))+splitPath (Path ar pcs fd) =+ (isAbsolutePlain ar,+ map (\pc -> Path Rel [pc] Dir) pcs,+ maybeFileDir fd)++isAbsolutePlain :: (AbsOrRelClass ar) => ar -> Bool+isAbsolutePlain = absRelPlain (const True) False++maybeFileDir :: (FileDirClass fd) => fd -> Maybe (RelFile os)+maybeFileDir = fileDirPlain (Just . Path Rel [] . File) Nothing++-- | This function can be used to construct a relative path by removing+-- the supplied 'AbsDir' from the front. It is a runtime 'error' if the+-- supplied 'AbsPath' doesn't start with the 'AbsDir'.+--+-- >> Path.makeRelative (absDir "/tmp/somedir") (absFile "/tmp/somedir/anotherdir/file.txt") == Posix.relFile "anotherdir/file.txt"+-- >> Path.makeRelative (absDir "/tmp/somedir") (absDir "/tmp/somedir/anotherdir/dir") == Posix.relDir "anotherdir/dir"+-- >> Path.makeRelative (absDir "c:\\tmp\\somedir") (absFile "C:\\Tmp\\SomeDir\\AnotherDir\\File.txt") == Windows.relFile "AnotherDir\\File.txt"+-- >> Path.makeRelative (absDir "c:\\tmp\\somedir") (absDir "c:\\tmp\\somedir\\anotherdir\\dir") == Windows.relDir "anotherdir\\dir"+-- >> Path.makeRelative (absDir "c:tmp\\somedir") (absDir "c:tmp\\somedir\\anotherdir\\dir") == Windows.relDir "anotherdir\\dir"+makeRelative ::+ (System os, FileOrDirClass fd) =>+ AbsDir os -> AbsPath os fd -> RelPath os fd+makeRelative relTo orig =+ fromMaybe+ (error $+ printf "System.Path can't make (%s) relative to (%s)"+ (getPathString orig) (getPathString relTo)) $+ makeRelativeMaybe relTo orig++-- >> Path.makeRelativeMaybe (Posix.absDir "/tmp/somedir") (absFile "/tmp/anotherdir/file.txt") == Nothing+-- >> Path.makeRelativeMaybe (Posix.absDir "/Tmp") (absFile "/tmp/anotherdir/file.txt") == Nothing+-- >> Path.makeRelativeMaybe (Windows.absDir "\\Tmp") (absFile "\\tmp\\anotherdir\\file.txt") == Just (relFile "anotherdir\\file.txt")+makeRelativeMaybe ::+ (System os, FileOrDirClass fd) =>+ AbsDir os -> AbsPath os fd -> Maybe (RelPath os fd)+makeRelativeMaybe relTo orig =+ case (inspectPath relTo, inspectPath orig) of+ ((relToAR, relToPCs, WrapFileDir Dir),+ (origAR, origPCs, WrapFileDir fd)) ->+ fmap (flip (Path Rel) fd) $+ guard (relToAR == origAR) >> stripPrefix relToPCs origPCs++-- | Joins an absolute directory with a relative path to construct a+-- new absolute path.+--+-- >> Path.makeAbsolute (absDir "/tmp") (relFile "file.txt") == Posix.absFile "/tmp/file.txt"+-- >> Path.makeAbsolute (absDir "/tmp") (relFile "adir/file.txt") == Posix.absFile "/tmp/adir/file.txt"+-- >> Path.makeAbsolute (absDir "/tmp") (relDir "adir/dir") == Posix.absDir "/tmp/adir/dir"+makeAbsolute :: (System os) => AbsDir os -> RelPath os fd -> AbsPath os fd+makeAbsolute = genericMakeAbsolute++-- | Converts a relative path into an absolute one by+-- prepending the current working directory.+makeAbsoluteFromCwd :: (System os) => RelPath os fd -> IO (AbsPath os fd)+makeAbsoluteFromCwd = genericMakeAbsoluteFromCwd++dynamicMakeAbsolute ::+ (System os) => AbsDir os -> AbsOrRelPath os fd -> AbsPath os fd+dynamicMakeAbsolute = genericMakeAbsolute++dynamicMakeAbsoluteFromCwd ::+ (System os) => AbsOrRelPath os fd -> IO (AbsPath os fd)+dynamicMakeAbsoluteFromCwd = genericMakeAbsoluteFromCwd++-- | As for 'makeAbsolute', but for use when the path may already be+-- absolute (in which case it is left unchanged).+-- You should avoid the use of 'genericMakeAbsolute'-type functions,+-- because then you avoid to absolutize a path that was already absolutized.+--+-- >> Path.genericMakeAbsolute (absDir "/tmp") (relFile "file.txt") == Posix.absFile "/tmp/file.txt"+-- >> Path.genericMakeAbsolute (absDir "/tmp") (relFile "adir/file.txt") == Posix.absFile "/tmp/adir/file.txt"+-- >> Path.genericMakeAbsolute (absDir "/tmp") (absFile "/adir/file.txt") == Posix.absFile "/adir/file.txt"+genericMakeAbsolute ::+ (System os, AbsOrRelClass ar) => AbsDir os -> Path os ar fd -> AbsPath os fd+genericMakeAbsolute base p = absRel id (base </>) p++-- | As for 'makeAbsoluteFromCwd', but for use when the path may already be+-- absolute (in which case it is left unchanged).+genericMakeAbsoluteFromCwd ::+ (System os, AbsOrRelClass ar) => Path os ar fd -> IO (AbsPath os fd)+genericMakeAbsoluteFromCwd p = do+ cwdString <- SD.getCurrentDirectory -- we don't use System.Path.Directory impl here to avoid module cycle+ return $ genericMakeAbsolute (asAbsDir cwdString) p++prop_makeAbsoluteFromDir_endSame ::+ (System os) => AbsDir os -> RelFile os -> Property+prop_makeAbsoluteFromDir_endSame base p =+ property $ getPathString p `isSuffixOf` getPathString (makeAbsolute base p)++prop_makeAbsoluteFromDir_startSame ::+ (System os) => AbsDir os -> RelFile os -> Property+prop_makeAbsoluteFromDir_startSame base p =+ property $ getPathString base `isPrefixOf` getPathString (makeAbsolute base p)++-- prop_makeAbsoluteFromDir_startSameAbs :: AbsDir os -> AbsFile -> Property+-- prop_makeAbsoluteFromDir_startSameAbs base p = property $ show base `isPrefixOf` show (makeAbsolute base p)+++-- | Convert a file to a directory path.+-- Obviously, the corresponding disk object won't change accordingly.+-- The purpose of this function is to be an intermediate step+-- when deriving a directory name from a file name.+dirFromFile :: FilePath os ar -> DirPath os ar+dirFromFile p = uncurry Path (pathComponents p) Dir++-- | Convert a directory to a file path.+-- The function returns 'Nothing' if the directory path is empty.+-- The purpose of this function is to be an intermediate step+-- when deriving a file name from a directory name.+fileFromDir :: DirPath os ar -> Maybe (FilePath os ar)+fileFromDir = fileFromAny++toFileOrDir :: (FileOrDirClass fd) => Path os ar fd -> FileOrDirPath os ar+toFileOrDir p = uncurry Path (pathComponents p) FileOrDir++fromFileOrDir ::+ (FileOrDirClass fd) => FileOrDirPath os ar -> Maybe (Path os ar fd)+fromFileOrDir p =+ switchFileOrDirPath+ (fileFromFileOrDir p)+ (Just $ dirFromFileOrDir p)+ (Just p)++fileFromFileOrDir :: FileOrDirPath os ar -> Maybe (FilePath os ar)+fileFromFileOrDir = fileFromAny++fileFromAny :: Path os ar fd -> Maybe (FilePath os ar)+fileFromAny (Path ar pcs _) =+ fmap (uncurry (Path ar) . mapSnd (File . untagPC)) $ ListHT.viewR pcs++dirFromFileOrDir :: FileOrDirPath os ar -> DirPath os ar+dirFromFileOrDir (Path ar pcs FileOrDir) = Path ar pcs Dir+++------------------------------------------------------------------------+-- NYI - Not Yet Implemented++{-+splitSearchPath :: String -> [String]+getSearchPath :: IO [String]+splitDrive :: String -> (String, String)+joinDrive :: String -> String -> String+takeDrive :: String -> String+hasDrive :: String -> Bool+dropDrive :: String -> String+isDrive :: String -> Bool+isValid :: String -> Bool+makeValid :: String -> String+-}+++------------------------------------------------------------------------+-- Path Predicates++-- | Test whether a @'Path' ar fd@ is absolute.+--+-- >> Path.isAbsolute (Posix.absFile "/fred")+-- >> Path.isAbsolute (Windows.absFile "\\fred")+-- >> Path.isAbsolute (Windows.absFile "c:\\fred")+-- >> Path.isAbsolute (Windows.absFile "c:fred")+isAbsolute :: AbsOrRelClass ar => Path os ar fd -> Bool+isAbsolute = absRel (const True) (const False)++-- | Invariant - this should return True iff arg is of type @'Path' Rel _@+--+-- > isRelative = not . isAbsolute+-- >> Path.isRelative (Posix.relFile "fred")+-- >> Path.isRelative (Windows.relFile "fred")+isRelative :: AbsOrRelClass ar => Path os ar fd -> Bool+isRelative = not . isAbsolute+++{- |+Test whether the 'String' would correspond+to an absolute path if interpreted as a 'Path'.+-}+isAbsoluteString :: (System os) => Tagged os (String -> Bool)+isAbsoluteString =+ fmap (\split -> not . null . MS.evalState split) splitAbsolute++{- |+Test whether the 'String' would correspond+to a relative path if interpreted as a 'Path'.++> isRelativeString = not . isAbsoluteString+-}+isRelativeString :: (System os) => Tagged os (String -> Bool)+isRelativeString = (not .) <$> isAbsoluteString+++-- | Does the given filename have an extension?+--+-- >> null (Path.takeExtension x) == not (Path.hasAnExtension x)+hasAnExtension :: FilePath os ar -> Bool+hasAnExtension = not . null . snd . splitExtension++-- | Does the given filename have the given extension?+--+-- >> Path.hasExtension ".hs" (Posix.relFile "MyCode.hs")+-- >> Path.hasExtension ".hs" (Posix.relFile "MyCode.bak.hs")+-- >> not $ Path.hasExtension ".hs" (Posix.relFile "MyCode.hs.bak")+hasExtension :: String -> FilePath os ar -> Bool+hasExtension ext = (==ext) . snd . splitExtension+++------------------------------------------------------------------------+-- Separators++-- | File extension character+--+-- >> Posix.extSeparator == '.'+extSeparator :: Char+extSeparator = '.'++-- | The character that is used to separate the entries in the $PATH environment variable.+--+searchPathSeparator :: Char+searchPathSeparator = ':'++-- | Is the character an extension character?+--+-- >> Posix.isExtSeparator a == (a == Posix.extSeparator)+isExtSeparator :: Char -> Bool+isExtSeparator = (== extSeparator)++-- | Is the character a file separator?+--+-- >> Posix.isSearchPathSeparator a == (a == Posix.searchPathSeparator)+isSearchPathSeparator :: Char -> Bool+isSearchPathSeparator = (== searchPathSeparator)+++------------------------------------------------------------------------+-- Generic Manipulation Functions++-- These functions support manipulation of extensions on directories+-- as well as files. They have looser types than the corresponding+-- 'Basic Manipulation Functions', but it is expected that the basic+-- functions will be used more frequently as they provide more checks.++-- | This is a more flexible variant of 'addExtension' / '<.>' which can+-- work with files or directories+--+-- >> Path.genericAddExtension (absDir "/") "x" == Posix.absDir "/.x"+-- >> Path.genericAddExtension (absDir "/a") "x" == Posix.absDir "/a.x"+-- >> Path.genericAddExtension Path.emptyFile "x" == Posix.relFile ".x"+-- >> Path.genericAddExtension Path.emptyFile "" == Posix.emptyFile+genericAddExtension ::+ (FileOrDirClass fd) => Path os ar fd -> String -> Path os ar fd+genericAddExtension =+ flip $ \ext ->+ appEndo $ MonHT.when (not $ null ext) $+ switchFileOrDirPath+ (Endo $ flip addExtension ext)+ (Endo $ componentsAddExtension ext)+ (Endo $ componentsAddExtension ext)++componentsAddExtension :: String -> Path os ar fd -> Path os ar fd+componentsAddExtension ext (Path ar pcs0 fd) =+ let pcs = if null pcs0 then [emptyPC] else pcs0+ in Path ar (mapLast (flip addExtensionPC ext) pcs) fd++genericDropExtension :: (FileOrDirClass fd) => Path os ar fd -> Path os ar fd+genericDropExtension = fst . genericSplitExtension++genericDropExtensions :: (FileOrDirClass fd) => Path os ar fd -> Path os ar fd+genericDropExtensions = fst . genericSplitExtensions++genericSplitExtension ::+ (FileOrDirClass fd) => Path os ar fd -> (Path os ar fd, String)+genericSplitExtension =+ runSplitExtension $+ switchFileOrDirPath+ (SplitExtension splitExtension)+ (SplitExtension componentsSplitExtension)+ (SplitExtension componentsSplitExtension)++componentsSplitExtension :: Path os ar b -> (Path os ar b, String)+componentsSplitExtension (Path ar pcs fd) =+ mapFst (flip (Path ar) fd) $+ mapLastPair+ (error "genericSplitExtension: empty path")+ splitExtensionPC pcs++genericSplitExtensions ::+ (FileOrDirClass fd) => Path os ar fd -> (Path os ar fd, String)+genericSplitExtensions =+ runSplitExtension $+ switchFileOrDirPath+ (SplitExtension splitExtensions)+ (SplitExtension componentsSplitExtensions)+ (SplitExtension componentsSplitExtensions)++componentsSplitExtensions :: Path os ar b -> (Path os ar b, String)+componentsSplitExtensions (Path ar pcs fd) =+ mapFst (flip (Path ar) fd) $+ mapLastPair+ (error "genericSplitExtensions: empty path")+ splitExtensionsPC pcs++genericTakeExtension :: (FileOrDirClass fd) => Path os ar fd -> String+genericTakeExtension = snd . genericSplitExtension++genericTakeExtensions :: (FileOrDirClass fd) => Path os ar fd -> String+genericTakeExtensions = snd . genericSplitExtension++newtype+ SplitExtension path =+ SplitExtension {runSplitExtension :: path -> (path, String)}+++-- move to utility-ht+mapLast :: (a -> a) -> [a] -> [a]+mapLast f xs = zipWith id (drop 1 $ map (const id) xs ++ [f]) xs++mapLastPair :: b -> (a -> (a,b)) -> [a] -> ([a], b)+mapLastPair b f =+ ListHT.switchR ([], b) (\as a -> mapFst ((as++) . (:[])) $ f a)++mapLastPairFoldr :: b -> (a -> (a,b)) -> [a] -> ([a], b)+mapLastPairFoldr b _ [] = ([], b)+mapLastPairFoldr _ f (x:xs) =+ foldr+ (\y1 go y0 -> mapFst (y0:) $ go y1)+ (\y -> mapFst (:[]) $ f y)+ xs x++mapLastPairRec :: b -> (a -> (a,b)) -> [a] -> ([a], b)+mapLastPairRec b _ [] = ([], b)+mapLastPairRec _ f (x:xs) =+ let go y [] = mapFst (:[]) $ f y+ go y0 (y1:ys) = mapFst (y0:) $ go y1 ys+ in go x xs++mapLastPairRev :: b -> (a -> (a,b)) -> [a] -> ([a], b)+mapLastPairRev b0 f xs =+ case reverse xs of+ [] -> (xs, b0)+ y:ys ->+ let (a, b) = f y+ in (reverse ys ++ [a], b)++_prop_mapLastPair :: String -> Int -> [String] -> Bool+_prop_mapLastPair b n strs =+ let f = splitAt n+ in all (mapLastPair b f strs ==) $+ mapLastPairFoldr b f strs :+ mapLastPairRev b f strs :+ mapLastPairRec b f strs :+ []+++addExtensionPC :: PathComponent os -> String -> PathComponent os+addExtensionPC p "" = p+addExtensionPC (PathComponent pc) ext =+ PathComponent $ pc +++ if [extSeparator] `isPrefixOf` ext+ then ext+ else extSeparator : ext++splitExtensionPC :: PathComponent os -> (PathComponent os, String)+splitExtensionPC (PathComponent s) =+ mapFst PathComponent $+ maybe (s, "") (mapFst concat) $+ ((\p@(pcs,_) -> toMaybe (not (null pcs)) p) =<<) $ ListHT.viewR $+ ListHT.segmentBefore isExtSeparator s++_splitExtensionPC :: PathComponent os -> (PathComponent os, String)+_splitExtensionPC (PathComponent s) =+ mapFst PathComponent $+ case break isExtSeparator $ reverse s of+ (_, "") -> (s, "")+ (rext, dot:rstem) -> (reverse rstem, dot : reverse rext)++splitExtensionsPC :: PathComponent os -> (PathComponent os, String)+splitExtensionsPC (PathComponent s) =+ mapFst PathComponent $ break isExtSeparator s++++class System os where+ -- | The character that separates directories. In the case where more than+ -- one character is possible, 'pathSeparator' is the \'ideal\' one.+ --+ -- >> Posix.isPathSeparator Posix.pathSeparator+ pathSeparator :: Tagged os Char++ -- | The list of all possible separators.+ --+ -- >> Posix.pathSeparator `elem` Posix.pathSeparators+ pathSeparators :: Tagged os [Char]+ pathSeparators = (:[]) <$> pathSeparator++ -- | Rather than using @(== 'pathSeparator')@, use this. Test if something+ -- is a path separator.+ --+ -- >> Posix.isPathSeparator a == (a `elem` Posix.pathSeparators)+ isPathSeparator :: Tagged os (Char -> Bool)+ isPathSeparator = flip elem <$> pathSeparators++ splitAbsolute :: Tagged os (MS.State String String)++ canonicalize :: Tagged os (String -> String)++ splitDrive :: Tagged os (MS.State String String)+ genDrive :: Tagged os (Gen String)+++{- |+Check internal integrity of the path data structure.+-}+isValid ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Path os ar fd -> Bool+isValid = untag isValidTagged++isValidTagged ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Tagged os (Path os ar fd -> Bool)+isValidTagged =+ fmap+ (\isValidPC (Path ar pcs fd) ->+ absRelPlain isValidComponent True ar+ &&+ all isValidPC pcs+ &&+ fileOrDirPlain (isValidPC . retagPC) True True fd)+ isValidPathComponent++isValidComponent :: String -> Bool+isValidComponent = not . null++isValidPathComponent ::+ (System os) => Tagged os (PathComponent os -> Bool)+isValidPathComponent =+ fmap+ (\isSep (PathComponent str) ->+ isValidComponent str && not (any isSep str))+ isPathSeparator++------------------------------------------------------------------------+-- QuickCheck++testAll :: (System os) => os -> [(String, IO ())]+testAll os =+ ("asPath_getPathString",+ quickCheck os prop_asPath_getPathString) :+ ("mkPathFromComponents_pathComponents",+ quickCheck os prop_mkPathFromComponents_pathComponents) :+ ("combine_currentDir",+ quickCheck os prop_combine_currentDir) :+ ("makeAbsoluteFromDir_endSame",+ quickCheck os prop_makeAbsoluteFromDir_endSame) :+ ("makeAbsoluteFromDir_startSame",+ quickCheck os prop_makeAbsoluteFromDir_startSame) :+ ("split_combine",+ quickCheck os prop_split_combine) :+ ("takeFileName_end",+ quickCheck os prop_takeFileName_end) :+ ("split_combineExt",+ quickCheck os prop_split_combineExt) :+ []++quickCheck ::+ (QC.Testable prop, System os, FileOrDirClass fd, AbsOrRelClass ar) =>+ os -> (Path os ar fd -> prop) -> IO ()+quickCheck _ = QC.quickCheck++-- test :: Testable a => a -> IO ()+-- test = quickCheck++qcFileComponent :: Gen (PathComponent os)+qcFileComponent = PathComponent <$> frequency [+ (1, return "someFile"),+ (1, return "fileWith.ext"),+ (1, return "file.with.multiple.exts"),+ (1, return "file with spcs")+ ]++qcDirComponent :: Gen (PathComponent os)+qcDirComponent = PathComponent <$> frequency [+ (1, return "someDir"),+ (1, return "aDir"),+ (1, return "aFolder"),+ (1, return "a folder"),+ (1, return "directory")+ ]+++qcAbsRel :: (System os, AbsOrRelClass ar) => Tagged os (Gen ar)+qcAbsRel =+ flip fmap genDrive $ \drive ->+ switchAbsOrRel (fmap absPC drive) (return Rel)+ (QC.oneof [fmap (AbsO . PathComponent) drive, return RelO])++qcGenPath ::+ Tagged os (Gen ar) ->+ (Gen ar -> Gen (Path os ar fd)) ->+ Gen (Path os ar fd)+qcGenPath qcAR gen = gen $ untag qcAR++qcFilePath :: (System os, AbsOrRelClass ar) => Gen (FilePath os ar)+qcFilePath = qcGenPath qcAbsRel $ \qcAR -> do+ ar <- qcAR+ pcs <- QC.listOf qcDirComponent+ pc <- qcFileComponent+ return $ Path ar pcs $ File pc++qcDirPath :: (System os, AbsOrRelClass ar) => fd -> Gen (Path os ar fd)+qcDirPath fd = qcGenPath qcAbsRel $ \qcAR -> do+ ar <- qcAR+ pcs <- QC.listOf qcDirComponent+ return $ Path ar pcs fd++qcPath ::+ (System os, AbsOrRelClass ar, FileOrDirClass fd) => Gen (Path os ar fd)+qcPath = switchFileOrDirPath qcFilePath (qcDirPath Dir) (qcDirPath FileOrDir)++instance+ (System os, AbsOrRelClass ar, FileOrDirClass fd) =>+ Arbitrary (Path os ar fd) where arbitrary = qcPath
src/System/Path/Posix.hs view
@@ -1,7 +1,4 @@-{-# LANGUAGE CPP #-}-#define MODULE_NAME Posix-#define IS_WINDOWS False-+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} -- | This module provides type-safe access to filepath manipulations. -- -- Normally you would import 'System.Path' (which will use the@@ -9,9 +6,197 @@ -- However, importing this explicitly allows for manipulation of -- non-native paths. ---#ifdef __HADDOCK__-module System.Path.Posix where-#else-#include "Internal.hs"-#endif+module System.Path.Posix (+ Path,+ AbsFile, RelFile, AbsDir, RelDir,+ AbsPath, RelPath, FilePath, DirPath,+ AbsOrRelFile, AbsOrRelDir, AbsFileOrDir, RelFileOrDir,+ AbsOrRelPath, FileOrDirPath, AbsOrRelFileOrDir,+ asPath,+ asRelFile, asRelDir, asAbsFile, asAbsDir,+ asRelPath, asAbsPath, asFilePath, asDirPath,+ path, maybePath,+ relFile, relDir, absFile, absDir,+ relPath, absPath, filePath, dirPath,+ rootDir, currentDir, emptyFile,+ toString,+ isAbsoluteString, isRelativeString, equalFilePath,+ pathSeparator, pathSeparators, isPathSeparator,+ Core.extSeparator, Core.isExtSeparator,+ Core.searchPathSeparator, Core.isSearchPathSeparator,+ addTrailingPathSeparator, dropTrailingPathSeparator,+ hasTrailingPathSeparator,+ testAll,+ ) where +import qualified System.Path.RegularExpression as RegEx+import qualified System.Path.Internal as Core+import System.Path.Internal (+ Abs, Rel, AbsOrRel, File, Dir, FileOrDir,+ AbsRelClass, FileDirClass,+ AbsOrRelClass, FileOrDirClass,+ )++import Data.Tagged (Tagged(Tagged), untag)++import Prelude hiding (FilePath)+++data Posix = Posix++_osDummy :: Posix+_osDummy = Posix++type Path = Core.Path Posix++type AbsFile = Path Abs File+type RelFile = Path Rel File+type AbsDir = Path Abs Dir+type RelDir = Path Rel Dir+type AbsOrRelFile = Path AbsOrRel File+type AbsOrRelDir = Path AbsOrRel Dir+type AbsFileOrDir = Path Abs FileOrDir+type RelFileOrDir = Path Rel FileOrDir+type AbsOrRelFileOrDir = Path AbsOrRel FileOrDir++type AbsPath fd = Path Abs fd+type RelPath fd = Path Rel fd+type FilePath ar = Path ar File+type DirPath ar = Path ar Dir+type AbsOrRelPath fd = Path AbsOrRel fd+type FileOrDirPath ar = Path ar FileOrDir++{-# DEPRECATED asPath "Use 'maybePath', 'parsePath' or 'path' instead." #-}+asPath :: (AbsRelClass ar, FileDirClass fd) => String -> Path ar fd+asPath = Core.asPath++{-# DEPRECATED asRelFile "Use 'relFile' instead." #-}+asRelFile :: String -> RelFile+asRelFile = Core.asRelFile++{-# DEPRECATED asRelDir "Use 'relDir' instead." #-}+asRelDir :: String -> RelDir+asRelDir = Core.asRelDir++{-# DEPRECATED asAbsFile "Use 'absFile' instead." #-}+asAbsFile :: String -> AbsFile+asAbsFile = Core.asAbsFile++{-# DEPRECATED asAbsDir "Use 'absDir' instead." #-}+asAbsDir :: String -> AbsDir+asAbsDir = Core.asAbsDir++{-# DEPRECATED asRelPath "Use 'relPath' instead." #-}+asRelPath :: (FileDirClass fd) => String -> RelPath fd+asRelPath = Core.asRelPath++{-# DEPRECATED asAbsPath "Use 'absPath' instead." #-}+asAbsPath :: (FileDirClass fd) => String -> AbsPath fd+asAbsPath = Core.asAbsPath++{-# DEPRECATED asFilePath "Use 'filePath' instead." #-}+asFilePath :: (AbsRelClass ar) => String -> FilePath ar+asFilePath = Core.asFilePath++{-# DEPRECATED asDirPath "Use 'dirPath' instead." #-}+asDirPath :: (AbsRelClass ar) => String -> DirPath ar+asDirPath = Core.asDirPath+++maybePath ::+ (AbsOrRelClass ar, FileOrDirClass fd) => String -> Maybe (Path ar fd)+maybePath = Core.maybePath+++path :: (AbsOrRelClass ar, FileOrDirClass fd) => String -> Path ar fd+path = Core.path++relFile :: String -> RelFile+relFile = Core.relFile++relDir :: String -> RelDir+relDir = Core.relDir++absFile :: String -> AbsFile+absFile = Core.absFile++absDir :: String -> AbsDir+absDir = Core.absDir++relPath :: (FileOrDirClass fd) => String -> RelPath fd+relPath = Core.relPath++absPath :: (FileOrDirClass fd) => String -> AbsPath fd+absPath = Core.absPath++filePath :: (AbsOrRelClass ar) => String -> FilePath ar+filePath = Core.filePath++dirPath :: (AbsOrRelClass ar) => String -> DirPath ar+dirPath = Core.dirPath+++rootDir :: AbsDir+rootDir = Core.rootDir++currentDir :: RelDir+currentDir = Core.currentDir++emptyFile :: RelFile+emptyFile = Core.emptyFile+++toString :: (AbsOrRelClass ar, FileOrDirClass fd) => Path ar fd -> String+toString = Core.toString+++instance Core.System Posix where+ pathSeparator = Tagged pathSeparator+ splitAbsolute = Tagged $ RegEx.run $ RegEx.single isPathSeparator+ canonicalize = Tagged id+ splitDrive = Tagged $ return ""+ genDrive = Tagged $ return ""++withOS :: Tagged Posix a -> a+withOS = untag+++equalFilePath :: String -> String -> Bool+equalFilePath = withOS Core.equalFilePath++isAbsoluteString :: String -> Bool+isAbsoluteString = withOS Core.isAbsoluteString++isRelativeString :: String -> Bool+isRelativeString = withOS Core.isRelativeString+++pathSeparator :: Char+pathSeparator = '/'++pathSeparators :: [Char]+pathSeparators = withOS Core.pathSeparators++isPathSeparator :: Char -> Bool+isPathSeparator = withOS Core.isPathSeparator+++{-# DEPRECATED addTrailingPathSeparator "Use System.FilePath.addTrailingPathSeparator instead." #-}+{-# DEPRECATED dropTrailingPathSeparator "Use System.FilePath.dropTrailingPathSeparator instead." #-}+{-# DEPRECATED hasTrailingPathSeparator "Use System.FilePath.hasTrailingPathSeparator instead." #-}++-- | This is largely for 'System.FilePath' compatibility+addTrailingPathSeparator :: String -> String+addTrailingPathSeparator = (++[pathSeparator])++-- | This is largely for 'System.FilePath' compatibility+dropTrailingPathSeparator :: String -> String+dropTrailingPathSeparator = init++-- | This is largely for 'System.FilePath' compatibility+hasTrailingPathSeparator :: String -> Bool+hasTrailingPathSeparator = isPathSeparator . last+++testAll :: [(String, IO ())]+testAll = Core.testAll Posix
+ src/System/Path/RegularExpression.hs view
@@ -0,0 +1,31 @@+module System.Path.RegularExpression where++import qualified Control.Monad.Trans.State as MS+import Control.Monad (guard)+import Control.Applicative (liftA2, (<|>))++import qualified Data.List.HT as ListHT+import Data.Monoid (Monoid, mempty, mappend)+import Data.Maybe (fromMaybe)+++newtype Parser a = Parser (MS.StateT [a] Maybe [a])++instance Monoid (Parser a) where+ mempty = Parser $ return []+ mappend (Parser x) (Parser y) = Parser $ liftA2 (++) x y++infixr 5 -|-++(-|-) :: Parser a -> Parser a -> Parser a+Parser x -|- Parser y = Parser $ x <|> y++single :: (a -> Bool) -> Parser a+single p = Parser $ do+ c <- MS.StateT ListHT.viewL+ guard $ p c+ return [c]++run :: Parser a -> MS.State [a] [a]+run (Parser x) =+ MS.state $ \str -> fromMaybe ([], str) $ MS.runStateT x str
src/System/Path/Windows.hs view
@@ -1,7 +1,4 @@-{-# LANGUAGE CPP #-}-#define MODULE_NAME Windows-#define IS_WINDOWS True-+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} -- | This module provides type-safe access to filepath manipulations. -- -- Normally you would import 'System.Path' (which will use the@@ -9,9 +6,207 @@ -- However, importing this explicitly allows for manipulation of -- non-native paths. ---#ifdef __HADDOCK__-module System.Path.Windows where-#else-#include "Internal.hs"-#endif+module System.Path.Windows (+ Path,+ AbsFile, RelFile, AbsDir, RelDir,+ AbsPath, RelPath, FilePath, DirPath,+ AbsOrRelFile, AbsOrRelDir, AbsFileOrDir, RelFileOrDir,+ AbsOrRelPath, FileOrDirPath, AbsOrRelFileOrDir,+ asPath,+ asRelFile, asRelDir, asAbsFile, asAbsDir,+ asRelPath, asAbsPath, asFilePath, asDirPath,+ path, maybePath,+ relFile, relDir, absFile, absDir,+ relPath, absPath, filePath, dirPath,+ rootDir, currentDir, emptyFile,+ toString,+ isAbsoluteString, isRelativeString, equalFilePath,+ pathSeparator, pathSeparators, isPathSeparator,+ Core.extSeparator, Core.isExtSeparator,+ Core.searchPathSeparator, Core.isSearchPathSeparator,+ addTrailingPathSeparator, dropTrailingPathSeparator,+ hasTrailingPathSeparator,+ testAll,+ ) where +import qualified System.Path.RegularExpression as RegEx+import qualified System.Path.Internal as Core+import System.Path.RegularExpression ((-|-))+import System.Path.Internal (+ Abs, Rel, AbsOrRel, File, Dir, FileOrDir,+ AbsRelClass, FileDirClass,+ AbsOrRelClass, FileOrDirClass,+ )++import Data.Tagged (Tagged(Tagged), untag)+import Data.Char (isAlpha, toLower)+import Data.Monoid (mempty, (<>))++import qualified Test.QuickCheck as QC++import Prelude hiding (FilePath)+++data Windows = Windows++_osDummy :: Windows+_osDummy = Windows++type Path = Core.Path Windows++type AbsFile = Path Abs File+type RelFile = Path Rel File+type AbsDir = Path Abs Dir+type RelDir = Path Rel Dir+type AbsOrRelFile = Path AbsOrRel File+type AbsOrRelDir = Path AbsOrRel Dir+type AbsFileOrDir = Path Abs FileOrDir+type RelFileOrDir = Path Rel FileOrDir+type AbsOrRelFileOrDir = Path AbsOrRel FileOrDir++type AbsPath fd = Path Abs fd+type RelPath fd = Path Rel fd+type FilePath ar = Path ar File+type DirPath ar = Path ar Dir+type AbsOrRelPath fd = Path AbsOrRel fd+type FileOrDirPath ar = Path ar FileOrDir++{-# DEPRECATED asPath "Use 'maybePath', 'parsePath' or 'path' instead." #-}+asPath :: (AbsRelClass ar, FileDirClass fd) => String -> Path ar fd+asPath = Core.asPath++{-# DEPRECATED asRelFile "Use 'relFile' instead." #-}+asRelFile :: String -> RelFile+asRelFile = Core.asRelFile++{-# DEPRECATED asRelDir "Use 'relDir' instead." #-}+asRelDir :: String -> RelDir+asRelDir = Core.asRelDir++{-# DEPRECATED asAbsFile "Use 'absFile' instead." #-}+asAbsFile :: String -> AbsFile+asAbsFile = Core.asAbsFile++{-# DEPRECATED asAbsDir "Use 'absDir' instead." #-}+asAbsDir :: String -> AbsDir+asAbsDir = Core.asAbsDir++{-# DEPRECATED asRelPath "Use 'relPath' instead." #-}+asRelPath :: (FileDirClass fd) => String -> RelPath fd+asRelPath = Core.asRelPath++{-# DEPRECATED asAbsPath "Use 'absPath' instead." #-}+asAbsPath :: (FileDirClass fd) => String -> AbsPath fd+asAbsPath = Core.asAbsPath++{-# DEPRECATED asFilePath "Use 'filePath' instead." #-}+asFilePath :: (AbsRelClass ar) => String -> FilePath ar+asFilePath = Core.asFilePath++{-# DEPRECATED asDirPath "Use 'dirPath' instead." #-}+asDirPath :: (AbsRelClass ar) => String -> DirPath ar+asDirPath = Core.asDirPath+++maybePath ::+ (AbsOrRelClass ar, FileOrDirClass fd) => String -> Maybe (Path ar fd)+maybePath = Core.maybePath+++path :: (AbsOrRelClass ar, FileOrDirClass fd) => String -> Path ar fd+path = Core.path++relFile :: String -> RelFile+relFile = Core.relFile++relDir :: String -> RelDir+relDir = Core.relDir++absFile :: String -> AbsFile+absFile = Core.absFile++absDir :: String -> AbsDir+absDir = Core.absDir++relPath :: (FileOrDirClass fd) => String -> RelPath fd+relPath = Core.relPath++absPath :: (FileOrDirClass fd) => String -> AbsPath fd+absPath = Core.absPath++filePath :: (AbsOrRelClass ar) => String -> FilePath ar+filePath = Core.filePath++dirPath :: (AbsOrRelClass ar) => String -> DirPath ar+dirPath = Core.dirPath+++rootDir :: AbsDir+rootDir = Core.rootDir++currentDir :: RelDir+currentDir = Core.currentDir++emptyFile :: RelFile+emptyFile = Core.emptyFile+++toString :: (AbsOrRelClass ar, FileOrDirClass fd) => Path ar fd -> String+toString = Core.toString+++instance Core.System Windows where+ pathSeparator = Tagged pathSeparator+ splitAbsolute = Tagged $ RegEx.run $+ RegEx.single isPathSeparator+ -|-+ driveRegEx <> (RegEx.single isPathSeparator -|- mempty)+ canonicalize = Tagged $ map toLower+ splitDrive = Tagged $ RegEx.run driveRegEx+ genDrive = Tagged $ fmap (:":") $ QC.choose ('a', 'z')++driveRegEx :: RegEx.Parser Char+driveRegEx = RegEx.single isAlpha <> RegEx.single (':'==)++withOS :: Tagged Windows a -> a+withOS = untag++equalFilePath :: String -> String -> Bool+equalFilePath = withOS Core.equalFilePath++isAbsoluteString :: String -> Bool+isAbsoluteString = withOS Core.isAbsoluteString++isRelativeString :: String -> Bool+isRelativeString = withOS Core.isRelativeString+++pathSeparator :: Char+pathSeparator = '\\'++pathSeparators :: [Char]+pathSeparators = withOS Core.pathSeparators++isPathSeparator :: Char -> Bool+isPathSeparator = withOS Core.isPathSeparator+++{-# DEPRECATED addTrailingPathSeparator "Use System.FilePath.addTrailingPathSeparator instead." #-}+{-# DEPRECATED dropTrailingPathSeparator "Use System.FilePath.dropTrailingPathSeparator instead." #-}+{-# DEPRECATED hasTrailingPathSeparator "Use System.FilePath.hasTrailingPathSeparator instead." #-}++-- | This is largely for 'System.FilePath' compatibility+addTrailingPathSeparator :: String -> String+addTrailingPathSeparator = (++[pathSeparator])++-- | This is largely for 'System.FilePath' compatibility+dropTrailingPathSeparator :: String -> String+dropTrailingPathSeparator = init++-- | This is largely for 'System.FilePath' compatibility+hasTrailingPathSeparator :: String -> Bool+hasTrailingPathSeparator = isPathSeparator . last+++testAll :: [(String, IO ())]+testAll = Core.testAll Windows
test/Test.hs view
@@ -2,7 +2,9 @@ import TestResult (results) -import System.Path (rootDir, asRelDir, asRelFile, (</>), (<.>))+import qualified System.Path.Posix as Posix+import qualified System.Path.Windows as Windows+import System.Path (rootDir, relDir, relFile, (</>), (<.>)) import System.Random (newStdGen, random) import System.Exit (exitFailure) import Control.Monad (void)@@ -14,7 +16,7 @@ g <- newStdGen let (a,_g') = random g -- TODO - integrate with QuickCheck- x = rootDir </> asRelDir "tmp" </> asRelFile "someFile" <.> "ext"+ x = rootDir </> relDir "tmp" </> relFile "someFile" <.> "ext" let allResults = results a x void $ printf "Running %d tests...\n" $ length allResults@@ -27,3 +29,10 @@ putStrLn "Failed tests:" mapM_ putStrLn fails exitFailure++ putStrLn "Running QuickCheck tests ..."+ let runQC prefix =+ mapM_ $ \(name, test) -> putStr (prefix ++ name ++ ": ") >> test+ runQC "Posix." Posix.testAll+ runQC "Windows." Windows.testAll+ putStrLn "Tests completed."
test/TestResult.hs view
@@ -1,391 +1,564 @@ {- Do not edit! Created from test/TestTemplate.hs -}-{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} module TestResult (results) where +import qualified System.Path.Generic as Path import qualified System.Path.Posix as Posix import qualified System.Path.Windows as Windows-import System.Path ((</>), (<.>))+import System.Path.Generic ((</>), (<.>), relFile, relDir, absFile, absDir) import Data.Char (toLower) -results :: (Posix.AbsRelClass ar) => Char -> Posix.FilePath ar -> [(String, Bool)]+results ::+ (Path.AbsRelClass ar) => Char -> Posix.FilePath ar -> [(String, Bool)] results a x =- {-# LINE 255 "src/System/Path/Internal.hs" #-}- ("Posix.pathMap (map toLower) \"/tmp/Reports/SpreadSheets\" == Posix.asAbsDir \"/tmp/reports/spreadsheets\"",- Posix.pathMap (map toLower) "/tmp/Reports/SpreadSheets" == Posix.asAbsDir "/tmp/reports/spreadsheets") :- {-# LINE 322 "src/System/Path/Internal.hs" #-}- ("show (Posix.rootDir </> \"bla\" </> Posix.asRelFile \"blub\") == \"rootDir </> \\\"bla\\\" </> \\\"blub\\\"\"",- show (Posix.rootDir </> "bla" </> Posix.asRelFile "blub") == "rootDir </> \"bla\" </> \"blub\"") :- {-# LINE 323 "src/System/Path/Internal.hs" #-}- ("show (Just (Posix.rootDir </> \"bla\" </> Posix.asRelFile \"blub\")) == \"Just (rootDir </> \\\"bla\\\" </> \\\"blub\\\")\"",- show (Just (Posix.rootDir </> "bla" </> Posix.asRelFile "blub")) == "Just (rootDir </> \"bla\" </> \"blub\")") :- {-# LINE 324 "src/System/Path/Internal.hs" #-}- ("show (Posix.currentDir </> \"bla\" </> Posix.asRelFile \"blub\") == \"currentDir </> \\\"bla\\\" </> \\\"blub\\\"\"",- show (Posix.currentDir </> "bla" </> Posix.asRelFile "blub") == "currentDir </> \"bla\" </> \"blub\"") :- {-# LINE 325 "src/System/Path/Internal.hs" #-}- ("show (Just (Posix.currentDir </> \"bla\" </> Posix.asRelFile \"blub\")) == \"Just (currentDir </> \\\"bla\\\" </> \\\"blub\\\")\"",- show (Just (Posix.currentDir </> "bla" </> Posix.asRelFile "blub")) == "Just (currentDir </> \"bla\" </> \"blub\")") :- {-# LINE 326 "src/System/Path/Internal.hs" #-}- ("show (Windows.asAbsDir \"c:\" Windows.</> \"bla\" Windows.</> Windows.asRelFile \"blub\") == \"asAbsDir \\\"c:\\\" </> \\\"bla\\\" </> \\\"blub\\\"\"",- show (Windows.asAbsDir "c:" Windows.</> "bla" Windows.</> Windows.asRelFile "blub") == "asAbsDir \"c:\" </> \"bla\" </> \"blub\"") :- {-# LINE 327 "src/System/Path/Internal.hs" #-}- ("show (Just (Windows.asAbsDir \"c:\\\\\" Windows.</> \"bla\" Windows.</> Windows.asRelFile \"blub\")) == \"Just (asAbsDir \\\"c:\\\" </> \\\"bla\\\" </> \\\"blub\\\")\"",- show (Just (Windows.asAbsDir "c:\\" Windows.</> "bla" Windows.</> Windows.asRelFile "blub")) == "Just (asAbsDir \"c:\" </> \"bla\" </> \"blub\")") :- {-# LINE 348 "src/System/Path/Internal.hs" #-}- ("let path = Posix.rootDir </> \"bla\" </> Posix.asRelFile \"blub\" in read (show path) == path",- let path = Posix.rootDir </> "bla" </> Posix.asRelFile "blub" in read (show path) == path) :- {-# LINE 349 "src/System/Path/Internal.hs" #-}- ("let path = Just (Posix.rootDir </> \"bla\" </> Posix.asRelFile \"blub\") in read (show path) == path",- let path = Just (Posix.rootDir </> "bla" </> Posix.asRelFile "blub") in read (show path) == path) :- {-# LINE 350 "src/System/Path/Internal.hs" #-}- ("let path = Posix.currentDir </> \"bla\" </> Posix.asRelFile \"blub\" in read (show path) == path",- let path = Posix.currentDir </> "bla" </> Posix.asRelFile "blub" in read (show path) == path) :- {-# LINE 351 "src/System/Path/Internal.hs" #-}- ("let path = Just (Posix.currentDir </> \"bla\" </> Posix.asRelFile \"blub\") in read (show path) == path",- let path = Just (Posix.currentDir </> "bla" </> Posix.asRelFile "blub") in read (show path) == path) :- {-# LINE 352 "src/System/Path/Internal.hs" #-}- ("let path = Windows.rootDir Windows.</> \"bla\" Windows.</> Windows.asRelFile \"blub\" in read (show path) == path",- let path = Windows.rootDir Windows.</> "bla" Windows.</> Windows.asRelFile "blub" in read (show path) == path) :- {-# LINE 353 "src/System/Path/Internal.hs" #-}- ("let path = Just (Windows.rootDir Windows.</> \"bla\" Windows.</> Windows.asRelFile \"blub\") in read (show path) == path",- let path = Just (Windows.rootDir Windows.</> "bla" Windows.</> Windows.asRelFile "blub") in read (show path) == path) :- {-# LINE 444 "src/System/Path/Internal.hs" #-}- ("Posix.asPath \"/tmp\" == Posix.asAbsDir \"/tmp\"",- Posix.asPath "/tmp" == Posix.asAbsDir "/tmp") :- {-# LINE 445 "src/System/Path/Internal.hs" #-}- ("Posix.asPath \"file.txt\" == Posix.asRelFile \"file.txt\"",- Posix.asPath "file.txt" == Posix.asRelFile "file.txt") :- {-# LINE 446 "src/System/Path/Internal.hs" #-}- ("Posix.isAbsolute (Posix.asAbsDir \"/tmp\")",- Posix.isAbsolute (Posix.asAbsDir "/tmp")) :- {-# LINE 447 "src/System/Path/Internal.hs" #-}- ("Posix.isRelative (Posix.asRelDir \"/tmp\")",- Posix.isRelative (Posix.asRelDir "/tmp")) :- {-# LINE 448 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asPath \"/tmp\" :: Posix.AbsDir) == \"/tmp\"",- Posix.getPathString (Posix.asPath "/tmp" :: Posix.AbsDir) == "/tmp") :- {-# LINE 449 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asPath \"/tmp\" :: Posix.RelDir) == \"tmp\"",- Posix.getPathString (Posix.asPath "/tmp" :: Posix.RelDir) == "tmp") :- {-# LINE 450 "src/System/Path/Internal.hs" #-}- ("Windows.getPathString (Windows.asPath \"\\\\tmp\" :: Windows.AbsDir) == \"\\\\tmp\"",- Windows.getPathString (Windows.asPath "\\tmp" :: Windows.AbsDir) == "\\tmp") :- {-# LINE 451 "src/System/Path/Internal.hs" #-}- ("Windows.getPathString (Windows.asPath \"a:\\\\tmp\" :: Windows.AbsDir) == \"a:\\\\tmp\"",- Windows.getPathString (Windows.asPath "a:\\tmp" :: Windows.AbsDir) == "a:\\tmp") :- {-# LINE 452 "src/System/Path/Internal.hs" #-}- ("Windows.getPathString (Windows.asPath \"tmp\" :: Windows.RelDir) == \"tmp\"",- Windows.getPathString (Windows.asPath "tmp" :: Windows.RelDir) == "tmp") :- {-# LINE 465 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelFile \"file.txt\") == \"file.txt\"",- Posix.getPathString (Posix.asRelFile "file.txt") == "file.txt") :- {-# LINE 466 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelFile \"/file.txt\") == \"file.txt\"",- Posix.getPathString (Posix.asRelFile "/file.txt") == "file.txt") :- {-# LINE 467 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelFile \"tmp\") == \"tmp\"",- Posix.getPathString (Posix.asRelFile "tmp") == "tmp") :- {-# LINE 468 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelFile \"/tmp\") == \"tmp\"",- Posix.getPathString (Posix.asRelFile "/tmp") == "tmp") :- {-# LINE 474 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelDir \".\") == \".\"",- Posix.getPathString (Posix.asRelDir ".") == ".") :- {-# LINE 475 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelDir \"file.txt\") == \"file.txt\"",- Posix.getPathString (Posix.asRelDir "file.txt") == "file.txt") :- {-# LINE 476 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelDir \"/file.txt\") == \"file.txt\"",- Posix.getPathString (Posix.asRelDir "/file.txt") == "file.txt") :- {-# LINE 477 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelDir \"tmp\") == \"tmp\"",- Posix.getPathString (Posix.asRelDir "tmp") == "tmp") :- {-# LINE 478 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelDir \"/tmp\") == \"tmp\"",- Posix.getPathString (Posix.asRelDir "/tmp") == "tmp") :- {-# LINE 484 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsFile \"file.txt\") == \"/file.txt\"",- Posix.getPathString (Posix.asAbsFile "file.txt") == "/file.txt") :+ {-# LINE 355 "src/System/Path/Internal.hs" #-}+ ("Path.pathMap (map toLower) (absDir \"/tmp/Reports/SpreadSheets\") == Posix.absDir \"/tmp/reports/spreadsheets\"",+ Path.pathMap (map toLower) (absDir "/tmp/Reports/SpreadSheets") == Posix.absDir "/tmp/reports/spreadsheets") : {-# LINE 485 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsFile \"/file.txt\") == \"/file.txt\"",- Posix.getPathString (Posix.asAbsFile "/file.txt") == "/file.txt") :+ ("show (Posix.rootDir </> relDir \"bla\" </> relFile \"blub\") == \"rootDir </> relDir \\\"bla\\\" </> relFile \\\"blub\\\"\"",+ show (Posix.rootDir </> relDir "bla" </> relFile "blub") == "rootDir </> relDir \"bla\" </> relFile \"blub\"") : {-# LINE 486 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsFile \"tmp\") == \"/tmp\"",- Posix.getPathString (Posix.asAbsFile "tmp") == "/tmp") :+ ("show (Just (Posix.rootDir </> relDir \"bla\" </> relFile \"blub\")) == \"Just (rootDir </> relDir \\\"bla\\\" </> relFile \\\"blub\\\")\"",+ show (Just (Posix.rootDir </> relDir "bla" </> relFile "blub")) == "Just (rootDir </> relDir \"bla\" </> relFile \"blub\")") : {-# LINE 487 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsFile \"/tmp\") == \"/tmp\"",- Posix.getPathString (Posix.asAbsFile "/tmp") == "/tmp") :- {-# LINE 493 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsDir \"file.txt\") == \"/file.txt\"",- Posix.getPathString (Posix.asAbsDir "file.txt") == "/file.txt") :- {-# LINE 494 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsDir \"/file.txt\") == \"/file.txt\"",- Posix.getPathString (Posix.asAbsDir "/file.txt") == "/file.txt") :- {-# LINE 495 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsDir \"tmp\") == \"/tmp\"",- Posix.getPathString (Posix.asAbsDir "tmp") == "/tmp") :- {-# LINE 496 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsDir \"/tmp\") == \"/tmp\"",- Posix.getPathString (Posix.asAbsDir "/tmp") == "/tmp") :+ ("show (Posix.currentDir </> relDir \"bla\" </> relFile \"blub\") == \"currentDir </> relDir \\\"bla\\\" </> relFile \\\"blub\\\"\"",+ show (Posix.currentDir </> relDir "bla" </> relFile "blub") == "currentDir </> relDir \"bla\" </> relFile \"blub\"") :+ {-# LINE 488 "src/System/Path/Internal.hs" #-}+ ("show (Just (Posix.currentDir </> relDir \"bla\" </> relFile \"blub\")) == \"Just (currentDir </> relDir \\\"bla\\\" </> relFile \\\"blub\\\")\"",+ show (Just (Posix.currentDir </> relDir "bla" </> relFile "blub")) == "Just (currentDir </> relDir \"bla\" </> relFile \"blub\")") :+ {-# LINE 489 "src/System/Path/Internal.hs" #-}+ ("show (Windows.absDir \"c:\" </> relDir \"bla\" </> relFile \"blub\") == \"absDir \\\"c:\\\" </> relDir \\\"bla\\\" </> relFile \\\"blub\\\"\"",+ show (Windows.absDir "c:" </> relDir "bla" </> relFile "blub") == "absDir \"c:\" </> relDir \"bla\" </> relFile \"blub\"") :+ {-# LINE 490 "src/System/Path/Internal.hs" #-}+ ("show (Just (Windows.absDir \"c:\\\\\" </> relDir \"bla\" </> relFile \"blub\")) == \"Just (absDir \\\"c:\\\\\\\\\\\" </> relDir \\\"bla\\\" </> relFile \\\"blub\\\")\"",+ show (Just (Windows.absDir "c:\\" </> relDir "bla" </> relFile "blub")) == "Just (absDir \"c:\\\\\" </> relDir \"bla\" </> relFile \"blub\")") :+ {-# LINE 520 "src/System/Path/Internal.hs" #-}+ ("read \"rootDir\" == Posix.rootDir",+ read "rootDir" == Posix.rootDir) :+ {-# LINE 521 "src/System/Path/Internal.hs" #-}+ ("read \"rootDir\" == Windows.rootDir",+ read "rootDir" == Windows.rootDir) :+ {-# LINE 522 "src/System/Path/Internal.hs" #-}+ ("read \"currentDir\" == Posix.currentDir",+ read "currentDir" == Posix.currentDir) :+ {-# LINE 523 "src/System/Path/Internal.hs" #-}+ ("read \"currentDir\" == Windows.currentDir",+ read "currentDir" == Windows.currentDir) :+ {-# LINE 524 "src/System/Path/Internal.hs" #-}+ ("let path = Posix.rootDir </> relDir \"bla\" </> relFile \"blub\" in read (show path) == path",+ let path = Posix.rootDir </> relDir "bla" </> relFile "blub" in read (show path) == path) :+ {-# LINE 525 "src/System/Path/Internal.hs" #-}+ ("let path = Just (Posix.rootDir </> relDir \"bla\" </> relFile \"blub\") in read (show path) == path",+ let path = Just (Posix.rootDir </> relDir "bla" </> relFile "blub") in read (show path) == path) :+ {-# LINE 526 "src/System/Path/Internal.hs" #-}+ ("let path = Posix.currentDir </> relDir \"bla\" </> relFile \"blub\" in read (show path) == path",+ let path = Posix.currentDir </> relDir "bla" </> relFile "blub" in read (show path) == path) : {-# LINE 527 "src/System/Path/Internal.hs" #-}- ("Posix.mkPathAbsOrRel \"/tmp\" == Left (Posix.asAbsDir \"/tmp\")",- Posix.mkPathAbsOrRel "/tmp" == Left (Posix.asAbsDir "/tmp")) :+ ("let path = Just (Posix.currentDir </> relDir \"bla\" </> relFile \"blub\") in read (show path) == path",+ let path = Just (Posix.currentDir </> relDir "bla" </> relFile "blub") in read (show path) == path) : {-# LINE 528 "src/System/Path/Internal.hs" #-}- ("Posix.mkPathAbsOrRel \"tmp\" == Right (Posix.asRelDir \"tmp\")",- Posix.mkPathAbsOrRel "tmp" == Right (Posix.asRelDir "tmp")) :+ ("let path = Windows.rootDir </> relDir \"bla\" </> relFile \"blub\" in read (show path) == path",+ let path = Windows.rootDir </> relDir "bla" </> relFile "blub" in read (show path) == path) : {-# LINE 529 "src/System/Path/Internal.hs" #-}- ("Windows.mkPathAbsOrRel \"\\\\tmp\" == Left (Windows.asAbsDir \"\\\\tmp\")",- Windows.mkPathAbsOrRel "\\tmp" == Left (Windows.asAbsDir "\\tmp")) :+ ("let path = Just (Windows.rootDir </> relDir \"bla\" </> relFile \"blub\") in read (show path) == path",+ let path = Just (Windows.rootDir </> relDir "bla" </> relFile "blub") in read (show path) == path) : {-# LINE 530 "src/System/Path/Internal.hs" #-}- ("Windows.mkPathAbsOrRel \"d:\\\\tmp\" == Left (Windows.asAbsDir \"d:\\\\tmp\")",- Windows.mkPathAbsOrRel "d:\\tmp" == Left (Windows.asAbsDir "d:\\tmp")) :- {-# LINE 531 "src/System/Path/Internal.hs" #-}- ("Windows.mkPathAbsOrRel \"tmp\" == Right (Windows.asRelDir \"tmp\")",- Windows.mkPathAbsOrRel "tmp" == Right (Windows.asRelDir "tmp")) :- {-# LINE 556 "src/System/Path/Internal.hs" #-}- ("Posix.mkAbsPath \"/tmp\" \"foo.txt\" == Posix.asAbsFile \"/tmp/foo.txt\"",- Posix.mkAbsPath "/tmp" "foo.txt" == Posix.asAbsFile "/tmp/foo.txt") :- {-# LINE 557 "src/System/Path/Internal.hs" #-}- ("Posix.mkAbsPath \"/tmp\" \"/etc/foo.txt\" == Posix.asAbsFile \"/etc/foo.txt\"",- Posix.mkAbsPath "/tmp" "/etc/foo.txt" == Posix.asAbsFile "/etc/foo.txt") :- {-# LINE 649 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsDir \"/tmp\" </> Posix.asRelFile \"file.txt\") == \"/tmp/file.txt\"",- Posix.getPathString (Posix.asAbsDir "/tmp" </> Posix.asRelFile "file.txt") == "/tmp/file.txt") :- {-# LINE 650 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asAbsDir \"/tmp\" </> Posix.asRelDir \"dir\" </> Posix.asRelFile \"file.txt\") == \"/tmp/dir/file.txt\"",- Posix.getPathString (Posix.asAbsDir "/tmp" </> Posix.asRelDir "dir" </> Posix.asRelFile "file.txt") == "/tmp/dir/file.txt") :- {-# LINE 651 "src/System/Path/Internal.hs" #-}- ("Posix.getPathString (Posix.asRelDir \"dir\" </> Posix.asRelFile \"file.txt\") == \"dir/file.txt\"",- Posix.getPathString (Posix.asRelDir "dir" </> Posix.asRelFile "file.txt") == "dir/file.txt") :- {-# LINE 652 "src/System/Path/Internal.hs" #-}- ("Windows.getPathString (Windows.asAbsDir \"\\\\tmp\" Windows.</> Windows.asRelFile \"file.txt\") == \"\\\\tmp\\\\file.txt\"",- Windows.getPathString (Windows.asAbsDir "\\tmp" Windows.</> Windows.asRelFile "file.txt") == "\\tmp\\file.txt") :- {-# LINE 653 "src/System/Path/Internal.hs" #-}- ("Windows.getPathString (Windows.asAbsDir \"c:\\\\tmp\" Windows.</> Windows.asRelFile \"file.txt\") == \"c:\\\\tmp\\\\file.txt\"",- Windows.getPathString (Windows.asAbsDir "c:\\tmp" Windows.</> Windows.asRelFile "file.txt") == "c:\\tmp\\file.txt") :- {-# LINE 654 "src/System/Path/Internal.hs" #-}- ("Windows.getPathString (Windows.asAbsDir \"c:\" Windows.</> Windows.asRelDir \"tmp\" Windows.</> Windows.asRelFile \"file.txt\") == \"c:\\\\tmp\\\\file.txt\"",- Windows.getPathString (Windows.asAbsDir "c:" Windows.</> Windows.asRelDir "tmp" Windows.</> Windows.asRelFile "file.txt") == "c:\\tmp\\file.txt") :- {-# LINE 655 "src/System/Path/Internal.hs" #-}- ("Windows.getPathString (Windows.asRelDir \"dir\" Windows.</> Windows.asRelFile \"file.txt\") == \"dir\\\\file.txt\"",- Windows.getPathString (Windows.asRelDir "dir" Windows.</> Windows.asRelFile "file.txt") == "dir\\file.txt") :+ ("let path = Windows.absDir \"c:\" </> relDir \"bla\" </> relFile \"blub\" in read (show path) == path",+ let path = Windows.absDir "c:" </> relDir "bla" </> relFile "blub" in read (show path) == path) :+ {-# LINE 619 "src/System/Path/Internal.hs" #-}+ ("Posix.toString Path.rootDir == \"/\"",+ Posix.toString Path.rootDir == "/") :+ {-# LINE 620 "src/System/Path/Internal.hs" #-}+ ("Windows.toString Path.rootDir == \"\\\\\"",+ Windows.toString Path.rootDir == "\\") :+ {-# LINE 630 "src/System/Path/Internal.hs" #-}+ ("Posix.toString Path.currentDir == \".\"",+ Posix.toString Path.currentDir == ".") :+ {-# LINE 631 "src/System/Path/Internal.hs" #-}+ ("Windows.toString Path.currentDir == \".\"",+ Windows.toString Path.currentDir == ".") : {-# LINE 673 "src/System/Path/Internal.hs" #-}- ("Posix.addExtension (Posix.asRelFile \"file.txt\") \"bib\" == \"file.txt.bib\"",- Posix.addExtension (Posix.asRelFile "file.txt") "bib" == "file.txt.bib") :+ ("fmap Posix.toString (Posix.maybePath \"/\" :: Maybe Posix.AbsDir) == Just \"/\"",+ fmap Posix.toString (Posix.maybePath "/" :: Maybe Posix.AbsDir) == Just "/") : {-# LINE 674 "src/System/Path/Internal.hs" #-}- ("Posix.addExtension (Posix.asRelFile \"file.\") \".bib\" == \"file..bib\"",- Posix.addExtension (Posix.asRelFile "file.") ".bib" == "file..bib") :+ ("fmap Posix.toString (Posix.maybePath \"/\" :: Maybe Posix.AbsFile) == Nothing",+ fmap Posix.toString (Posix.maybePath "/" :: Maybe Posix.AbsFile) == Nothing) : {-# LINE 675 "src/System/Path/Internal.hs" #-}- ("Posix.addExtension (Posix.asRelFile \"file\") \".bib\" == \"file.bib\"",- Posix.addExtension (Posix.asRelFile "file") ".bib" == "file.bib") :+ ("fmap Posix.toString (Posix.maybePath \"/\" :: Maybe Posix.RelDir) == Nothing",+ fmap Posix.toString (Posix.maybePath "/" :: Maybe Posix.RelDir) == Nothing) : {-# LINE 676 "src/System/Path/Internal.hs" #-}- ("Posix.addExtension (Posix.asRelFile \"\") \"bib\" == \".bib\"",- Posix.addExtension (Posix.asRelFile "") "bib" == ".bib") :+ ("fmap Posix.toString (Posix.maybePath \"/\" :: Maybe Posix.RelFile) == Nothing",+ fmap Posix.toString (Posix.maybePath "/" :: Maybe Posix.RelFile) == Nothing) : {-# LINE 677 "src/System/Path/Internal.hs" #-}- ("Posix.addExtension (Posix.asRelFile \"\") \".bib\" == \".bib\"",- Posix.addExtension (Posix.asRelFile "") ".bib" == ".bib") :+ ("fmap Posix.toString (Posix.maybePath \"/tmp\" :: Maybe Posix.AbsDir) == Just \"/tmp\"",+ fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.AbsDir) == Just "/tmp") : {-# LINE 678 "src/System/Path/Internal.hs" #-}- ("Posix.takeFileName (Posix.addExtension (Posix.asRelFile \"\") \"ext\") == \".ext\"",- Posix.takeFileName (Posix.addExtension (Posix.asRelFile "") "ext") == ".ext") :+ ("fmap Posix.toString (Posix.maybePath \"/tmp\" :: Maybe Posix.AbsFile) == Just \"/tmp\"",+ fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.AbsFile) == Just "/tmp") :+ {-# LINE 679 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"/tmp\" :: Maybe Posix.RelDir) == Nothing",+ fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.RelDir) == Nothing) :+ {-# LINE 680 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"/tmp\" :: Maybe Posix.RelFile) == Nothing",+ fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.RelFile) == Nothing) :+ {-# LINE 681 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"/tmp/\" :: Maybe Posix.AbsDir) == Just \"/tmp\"",+ fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.AbsDir) == Just "/tmp") :+ {-# LINE 682 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"/tmp/\" :: Maybe Posix.AbsFile) == Nothing",+ fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.AbsFile) == Nothing) :+ {-# LINE 683 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"/tmp/\" :: Maybe Posix.RelDir) == Nothing",+ fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.RelDir) == Nothing) :+ {-# LINE 684 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"/tmp/\" :: Maybe Posix.RelFile) == Nothing",+ fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.RelFile) == Nothing) :+ {-# LINE 685 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"/tmp\" :: Maybe Posix.AbsOrRelFileOrDir) == Just \"/tmp\"",+ fmap Posix.toString (Posix.maybePath "/tmp" :: Maybe Posix.AbsOrRelFileOrDir) == Just "/tmp") :+ {-# LINE 686 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"/tmp/\" :: Maybe Posix.AbsOrRelFileOrDir) == Just \"/tmp\"",+ fmap Posix.toString (Posix.maybePath "/tmp/" :: Maybe Posix.AbsOrRelFileOrDir) == Just "/tmp") :+ {-# LINE 687 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"file.txt\" :: Maybe Posix.RelFile) == Just \"file.txt\"",+ fmap Posix.toString (Posix.maybePath "file.txt" :: Maybe Posix.RelFile) == Just "file.txt") :+ {-# LINE 688 "src/System/Path/Internal.hs" #-}+ ("fmap Posix.toString (Posix.maybePath \"file.txt\" :: Maybe Posix.AbsFile) == Nothing",+ fmap Posix.toString (Posix.maybePath "file.txt" :: Maybe Posix.AbsFile) == Nothing) :+ {-# LINE 689 "src/System/Path/Internal.hs" #-}+ ("fmap Windows.toString (Windows.maybePath \"\\\\tmp\" :: Maybe Windows.AbsDir) == Just \"\\\\tmp\"",+ fmap Windows.toString (Windows.maybePath "\\tmp" :: Maybe Windows.AbsDir) == Just "\\tmp") : {-# LINE 690 "src/System/Path/Internal.hs" #-}- ("Posix.dropExtension x == fst (Posix.splitExtension x)",- Posix.dropExtension x == fst (Posix.splitExtension x)) :+ ("fmap Windows.toString (Windows.maybePath \"a:\\\\tmp\" :: Maybe Windows.AbsDir) == Just \"a:\\\\tmp\"",+ fmap Windows.toString (Windows.maybePath "a:\\tmp" :: Maybe Windows.AbsDir) == Just "a:\\tmp") :+ {-# LINE 691 "src/System/Path/Internal.hs" #-}+ ("fmap Windows.toString (Windows.maybePath \"a:tmp\" :: Maybe Windows.AbsDir) == Just \"a:tmp\"",+ fmap Windows.toString (Windows.maybePath "a:tmp" :: Maybe Windows.AbsDir) == Just "a:tmp") :+ {-# LINE 692 "src/System/Path/Internal.hs" #-}+ ("fmap Windows.toString (Windows.maybePath \"a:\\\\\" :: Maybe Windows.AbsDir) == Just \"a:\\\\\"",+ fmap Windows.toString (Windows.maybePath "a:\\" :: Maybe Windows.AbsDir) == Just "a:\\") :+ {-# LINE 693 "src/System/Path/Internal.hs" #-}+ ("fmap Windows.toString (Windows.maybePath \"a:\" :: Maybe Windows.AbsDir) == Just \"a:\"",+ fmap Windows.toString (Windows.maybePath "a:" :: Maybe Windows.AbsDir) == Just "a:") :+ {-# LINE 694 "src/System/Path/Internal.hs" #-}+ ("fmap Windows.toString (Windows.maybePath \"tmp\" :: Maybe Windows.RelDir) == Just \"tmp\"",+ fmap Windows.toString (Windows.maybePath "tmp" :: Maybe Windows.RelDir) == Just "tmp") :+ {-# LINE 695 "src/System/Path/Internal.hs" #-}+ ("fmap Windows.toString (Windows.maybePath \"\\\\tmp\" :: Maybe Windows.RelDir) == Nothing",+ fmap Windows.toString (Windows.maybePath "\\tmp" :: Maybe Windows.RelDir) == Nothing) : {-# LINE 696 "src/System/Path/Internal.hs" #-}- ("not $ Posix.hasAnExtension (Posix.dropExtensions x)",- not $ Posix.hasAnExtension (Posix.dropExtensions x)) :- {-# LINE 707 "src/System/Path/Internal.hs" #-}- ("Posix.replaceExtension (Posix.asRelFile \"file.txt\") \".bob\" == \"file.bob\"",- Posix.replaceExtension (Posix.asRelFile "file.txt") ".bob" == "file.bob") :- {-# LINE 708 "src/System/Path/Internal.hs" #-}- ("Posix.replaceExtension (Posix.asRelFile \"file.txt\") \"bob\" == \"file.bob\"",- Posix.replaceExtension (Posix.asRelFile "file.txt") "bob" == "file.bob") :- {-# LINE 709 "src/System/Path/Internal.hs" #-}- ("Posix.replaceExtension (Posix.asRelFile \"file\") \".bob\" == \"file.bob\"",- Posix.replaceExtension (Posix.asRelFile "file") ".bob" == "file.bob") :- {-# LINE 710 "src/System/Path/Internal.hs" #-}- ("Posix.replaceExtension (Posix.asRelFile \"file.txt\") \"\" == \"file\"",- Posix.replaceExtension (Posix.asRelFile "file.txt") "" == "file") :- {-# LINE 711 "src/System/Path/Internal.hs" #-}- ("Posix.replaceExtension (Posix.asRelFile \"file.fred.bob\") \"txt\" == \"file.fred.txt\"",- Posix.replaceExtension (Posix.asRelFile "file.fred.bob") "txt" == "file.fred.txt") :- {-# LINE 729 "src/System/Path/Internal.hs" #-}- ("uncurry (<.>) (Posix.splitExtension x) == x",- uncurry (<.>) (Posix.splitExtension x) == x) :- {-# LINE 730 "src/System/Path/Internal.hs" #-}- ("uncurry Posix.addExtension (Posix.splitExtension x) == x",- uncurry Posix.addExtension (Posix.splitExtension x) == x) :- {-# LINE 731 "src/System/Path/Internal.hs" #-}- ("Posix.splitExtension (Posix.asRelFile \"file.txt\") == (\"file\",\".txt\")",- Posix.splitExtension (Posix.asRelFile "file.txt") == ("file",".txt")) :- {-# LINE 732 "src/System/Path/Internal.hs" #-}- ("Posix.splitExtension (Posix.asRelFile \"file\") == (\"file\",\"\")",- Posix.splitExtension (Posix.asRelFile "file") == ("file","")) :- {-# LINE 733 "src/System/Path/Internal.hs" #-}- ("Posix.splitExtension (Posix.asRelFile \"file/file.txt\") == (\"file/file\",\".txt\")",- Posix.splitExtension (Posix.asRelFile "file/file.txt") == ("file/file",".txt")) :- {-# LINE 734 "src/System/Path/Internal.hs" #-}- ("Posix.splitExtension (Posix.asRelFile \"file.txt/boris\") == (\"file.txt/boris\",\"\")",- Posix.splitExtension (Posix.asRelFile "file.txt/boris") == ("file.txt/boris","")) :- {-# LINE 735 "src/System/Path/Internal.hs" #-}- ("Posix.splitExtension (Posix.asRelFile \"file.txt/boris.ext\") == (\"file.txt/boris\",\".ext\")",- Posix.splitExtension (Posix.asRelFile "file.txt/boris.ext") == ("file.txt/boris",".ext")) :- {-# LINE 736 "src/System/Path/Internal.hs" #-}- ("Posix.splitExtension (Posix.asRelFile \"file/path.txt.bob.fred\") == (\"file/path.txt.bob\",\".fred\")",- Posix.splitExtension (Posix.asRelFile "file/path.txt.bob.fred") == ("file/path.txt.bob",".fred")) :- {-# LINE 743 "src/System/Path/Internal.hs" #-}- ("Posix.splitExtensions (Posix.asRelFile \"file.tar.gz\") == (\"file\",\".tar.gz\")",- Posix.splitExtensions (Posix.asRelFile "file.tar.gz") == ("file",".tar.gz")) :- {-# LINE 760 "src/System/Path/Internal.hs" #-}- ("Posix.takeBaseName (Posix.asAbsFile \"/tmp/somedir/myfile.txt\") == \"myfile\"",- Posix.takeBaseName (Posix.asAbsFile "/tmp/somedir/myfile.txt") == "myfile") :- {-# LINE 761 "src/System/Path/Internal.hs" #-}- ("Posix.takeBaseName (Posix.asRelFile \"./myfile.txt\") == \"myfile\"",- Posix.takeBaseName (Posix.asRelFile "./myfile.txt") == "myfile") :+ ("fmap Windows.toString (Windows.maybePath \"a:\\\\tmp\" :: Maybe Windows.RelDir) == Nothing",+ fmap Windows.toString (Windows.maybePath "a:\\tmp" :: Maybe Windows.RelDir) == Nothing) :+ {-# LINE 697 "src/System/Path/Internal.hs" #-}+ ("fmap Windows.toString (Windows.maybePath \"a:tmp\" :: Maybe Windows.RelDir) == Nothing",+ fmap Windows.toString (Windows.maybePath "a:tmp" :: Maybe Windows.RelDir) == Nothing) :+ {-# LINE 698 "src/System/Path/Internal.hs" #-}+ ("fmap Windows.toString (Windows.maybePath \"tmp\" :: Maybe Windows.AbsDir) == Nothing",+ fmap Windows.toString (Windows.maybePath "tmp" :: Maybe Windows.AbsDir) == Nothing) :+ {-# LINE 747 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.relFile \"file.txt\") == \"file.txt\"",+ Posix.toString (Posix.relFile "file.txt") == "file.txt") :+ {-# LINE 748 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.relFile \"tmp\") == \"tmp\"",+ Posix.toString (Posix.relFile "tmp") == "tmp") :+ {-# LINE 754 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.relDir \".\") == \".\"",+ Posix.toString (Posix.relDir ".") == ".") :+ {-# LINE 755 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.relDir \"file.txt\") == \"file.txt\"",+ Posix.toString (Posix.relDir "file.txt") == "file.txt") :+ {-# LINE 756 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.relDir \"tmp\") == \"tmp\"",+ Posix.toString (Posix.relDir "tmp") == "tmp") : {-# LINE 762 "src/System/Path/Internal.hs" #-}- ("Posix.takeBaseName (Posix.asRelFile \"myfile.txt\") == \"myfile\"",- Posix.takeBaseName (Posix.asRelFile "myfile.txt") == "myfile") :- {-# LINE 771 "src/System/Path/Internal.hs" #-}- ("Posix.takeExtension x == snd (Posix.splitExtension x)",- Posix.takeExtension x == snd (Posix.splitExtension x)) :- {-# LINE 772 "src/System/Path/Internal.hs" #-}- ("Posix.takeExtension (Posix.addExtension x \"ext\") == \".ext\"",- Posix.takeExtension (Posix.addExtension x "ext") == ".ext") :- {-# LINE 773 "src/System/Path/Internal.hs" #-}- ("Posix.takeExtension (Posix.replaceExtension x \"ext\") == \".ext\"",- Posix.takeExtension (Posix.replaceExtension x "ext") == ".ext") :- {-# LINE 779 "src/System/Path/Internal.hs" #-}- ("Posix.takeExtensions (Posix.asRelFile \"file.tar.gz\") == \".tar.gz\"",- Posix.takeExtensions (Posix.asRelFile "file.tar.gz") == ".tar.gz") :- {-# LINE 785 "src/System/Path/Internal.hs" #-}- ("Posix.takeFileName (Posix.asAbsFile \"/tmp/somedir/myfile.txt\") == \"myfile.txt\"",- Posix.takeFileName (Posix.asAbsFile "/tmp/somedir/myfile.txt") == "myfile.txt") :- {-# LINE 786 "src/System/Path/Internal.hs" #-}- ("Posix.takeFileName (Posix.asRelFile \"./myfile.txt\") == \"myfile.txt\"",- Posix.takeFileName (Posix.asRelFile "./myfile.txt") == "myfile.txt") :- {-# LINE 787 "src/System/Path/Internal.hs" #-}- ("Posix.takeFileName (Posix.asRelFile \"myfile.txt\") == \"myfile.txt\"",- Posix.takeFileName (Posix.asRelFile "myfile.txt") == "myfile.txt") :- {-# LINE 800 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.absFile \"/file.txt\") == \"/file.txt\"",+ Posix.toString (Posix.absFile "/file.txt") == "/file.txt") :+ {-# LINE 763 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.absFile \"/tmp\") == \"/tmp\"",+ Posix.toString (Posix.absFile "/tmp") == "/tmp") :+ {-# LINE 769 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.absDir \"/file.txt\") == \"/file.txt\"",+ Posix.toString (Posix.absDir "/file.txt") == "/file.txt") :+ {-# LINE 770 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.absDir \"/tmp\") == \"/tmp\"",+ Posix.toString (Posix.absDir "/tmp") == "/tmp") :+ {-# LINE 835 "src/System/Path/Internal.hs" #-}+ ("Posix.asPath \"/tmp\" == Posix.absDir \"/tmp\"",+ Posix.asPath "/tmp" == Posix.absDir "/tmp") :+ {-# LINE 836 "src/System/Path/Internal.hs" #-}+ ("Posix.asPath \"file.txt\" == Posix.relFile \"file.txt\"",+ Posix.asPath "file.txt" == Posix.relFile "file.txt") :+ {-# LINE 837 "src/System/Path/Internal.hs" #-}+ ("Path.isAbsolute (Posix.asAbsDir \"/tmp\")",+ Path.isAbsolute (Posix.asAbsDir "/tmp")) :+ {-# LINE 838 "src/System/Path/Internal.hs" #-}+ ("Path.isRelative (Posix.asRelDir \"/tmp\")",+ Path.isRelative (Posix.asRelDir "/tmp")) :+ {-# LINE 839 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asPath \"/tmp\" :: Posix.AbsDir) == \"/tmp\"",+ Posix.toString (Posix.asPath "/tmp" :: Posix.AbsDir) == "/tmp") :+ {-# LINE 840 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asPath \"/tmp\" :: Posix.RelDir) == \"tmp\"",+ Posix.toString (Posix.asPath "/tmp" :: Posix.RelDir) == "tmp") :+ {-# LINE 841 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.asPath \"\\\\tmp\" :: Windows.AbsDir) == \"\\\\tmp\"",+ Windows.toString (Windows.asPath "\\tmp" :: Windows.AbsDir) == "\\tmp") :+ {-# LINE 842 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.asPath \"a:\\\\tmp\" :: Windows.AbsDir) == \"a:\\\\tmp\"",+ Windows.toString (Windows.asPath "a:\\tmp" :: Windows.AbsDir) == "a:\\tmp") :+ {-# LINE 843 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.asPath \"a:tmp\" :: Windows.AbsDir) == \"a:tmp\"",+ Windows.toString (Windows.asPath "a:tmp" :: Windows.AbsDir) == "a:tmp") :+ {-# LINE 844 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.asPath \"tmp\" :: Windows.RelDir) == \"tmp\"",+ Windows.toString (Windows.asPath "tmp" :: Windows.RelDir) == "tmp") :+ {-# LINE 852 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asRelFile \"file.txt\") == \"file.txt\"",+ Posix.toString (Posix.asRelFile "file.txt") == "file.txt") :+ {-# LINE 853 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asRelFile \"/file.txt\") == \"file.txt\"",+ Posix.toString (Posix.asRelFile "/file.txt") == "file.txt") :+ {-# LINE 854 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asRelFile \"tmp\") == \"tmp\"",+ Posix.toString (Posix.asRelFile "tmp") == "tmp") :+ {-# LINE 855 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asRelFile \"/tmp\") == \"tmp\"",+ Posix.toString (Posix.asRelFile "/tmp") == "tmp") :+ {-# LINE 861 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asRelDir \".\") == \".\"",+ Posix.toString (Posix.asRelDir ".") == ".") :+ {-# LINE 862 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asRelDir \"file.txt\") == \"file.txt\"",+ Posix.toString (Posix.asRelDir "file.txt") == "file.txt") :+ {-# LINE 863 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asRelDir \"/file.txt\") == \"file.txt\"",+ Posix.toString (Posix.asRelDir "/file.txt") == "file.txt") :+ {-# LINE 864 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asRelDir \"tmp\") == \"tmp\"",+ Posix.toString (Posix.asRelDir "tmp") == "tmp") :+ {-# LINE 865 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asRelDir \"/tmp\") == \"tmp\"",+ Posix.toString (Posix.asRelDir "/tmp") == "tmp") :+ {-# LINE 871 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asAbsFile \"/file.txt\") == \"/file.txt\"",+ Posix.toString (Posix.asAbsFile "/file.txt") == "/file.txt") :+ {-# LINE 872 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asAbsFile \"/tmp\") == \"/tmp\"",+ Posix.toString (Posix.asAbsFile "/tmp") == "/tmp") :+ {-# LINE 878 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asAbsDir \"/file.txt\") == \"/file.txt\"",+ Posix.toString (Posix.asAbsDir "/file.txt") == "/file.txt") :+ {-# LINE 879 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.asAbsDir \"/tmp\") == \"/tmp\"",+ Posix.toString (Posix.asAbsDir "/tmp") == "/tmp") :+ {-# LINE 916 "src/System/Path/Internal.hs" #-}+ ("Path.mkPathAbsOrRel \"/tmp\" == Left (Posix.absDir \"/tmp\")",+ Path.mkPathAbsOrRel "/tmp" == Left (Posix.absDir "/tmp")) :+ {-# LINE 917 "src/System/Path/Internal.hs" #-}+ ("Path.mkPathAbsOrRel \"tmp\" == Right (Posix.relDir \"tmp\")",+ Path.mkPathAbsOrRel "tmp" == Right (Posix.relDir "tmp")) :+ {-# LINE 918 "src/System/Path/Internal.hs" #-}+ ("Path.mkPathAbsOrRel \"\\\\tmp\" == Left (Windows.absDir \"\\\\tmp\")",+ Path.mkPathAbsOrRel "\\tmp" == Left (Windows.absDir "\\tmp")) :+ {-# LINE 919 "src/System/Path/Internal.hs" #-}+ ("Path.mkPathAbsOrRel \"d:\\\\tmp\" == Left (Windows.absDir \"d:\\\\tmp\")",+ Path.mkPathAbsOrRel "d:\\tmp" == Left (Windows.absDir "d:\\tmp")) :+ {-# LINE 920 "src/System/Path/Internal.hs" #-}+ ("Path.mkPathAbsOrRel \"d:tmp\" == Left (Windows.absDir \"d:tmp\")",+ Path.mkPathAbsOrRel "d:tmp" == Left (Windows.absDir "d:tmp")) :+ {-# LINE 921 "src/System/Path/Internal.hs" #-}+ ("Path.mkPathAbsOrRel \"tmp\" == Right (Windows.relDir \"tmp\")",+ Path.mkPathAbsOrRel "tmp" == Right (Windows.relDir "tmp")) :+ {-# LINE 951 "src/System/Path/Internal.hs" #-}+ ("Path.mkAbsPath (absDir \"/tmp\") \"foo.txt\" == Posix.absFile \"/tmp/foo.txt\"",+ Path.mkAbsPath (absDir "/tmp") "foo.txt" == Posix.absFile "/tmp/foo.txt") :+ {-# LINE 952 "src/System/Path/Internal.hs" #-}+ ("Path.mkAbsPath (absDir \"/tmp\") \"/etc/foo.txt\" == Posix.absFile \"/etc/foo.txt\"",+ Path.mkAbsPath (absDir "/tmp") "/etc/foo.txt" == Posix.absFile "/etc/foo.txt") :+ {-# LINE 1089 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.absDir \"/tmp\" </> Posix.relFile \"file.txt\") == \"/tmp/file.txt\"",+ Posix.toString (Posix.absDir "/tmp" </> Posix.relFile "file.txt") == "/tmp/file.txt") :+ {-# LINE 1090 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.absDir \"/tmp\" </> Posix.relDir \"dir\" </> Posix.relFile \"file.txt\") == \"/tmp/dir/file.txt\"",+ Posix.toString (Posix.absDir "/tmp" </> Posix.relDir "dir" </> Posix.relFile "file.txt") == "/tmp/dir/file.txt") :+ {-# LINE 1091 "src/System/Path/Internal.hs" #-}+ ("Posix.toString (Posix.relDir \"dir\" </> Posix.relFile \"file.txt\") == \"dir/file.txt\"",+ Posix.toString (Posix.relDir "dir" </> Posix.relFile "file.txt") == "dir/file.txt") :+ {-# LINE 1092 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.absDir \"\\\\tmp\" </> Windows.relFile \"file.txt\") == \"\\\\tmp\\\\file.txt\"",+ Windows.toString (Windows.absDir "\\tmp" </> Windows.relFile "file.txt") == "\\tmp\\file.txt") :+ {-# LINE 1093 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.absDir \"c:\\\\tmp\" </> Windows.relFile \"file.txt\") == \"c:\\\\tmp\\\\file.txt\"",+ Windows.toString (Windows.absDir "c:\\tmp" </> Windows.relFile "file.txt") == "c:\\tmp\\file.txt") :+ {-# LINE 1094 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.absDir \"c:tmp\" </> Windows.relFile \"file.txt\") == \"c:tmp\\\\file.txt\"",+ Windows.toString (Windows.absDir "c:tmp" </> Windows.relFile "file.txt") == "c:tmp\\file.txt") :+ {-# LINE 1095 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.absDir \"c:\\\\\" </> Windows.relDir \"tmp\" </> Windows.relFile \"file.txt\") == \"c:\\\\tmp\\\\file.txt\"",+ Windows.toString (Windows.absDir "c:\\" </> Windows.relDir "tmp" </> Windows.relFile "file.txt") == "c:\\tmp\\file.txt") :+ {-# LINE 1096 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.absDir \"c:\" </> Windows.relDir \"tmp\" </> Windows.relFile \"file.txt\") == \"c:tmp\\\\file.txt\"",+ Windows.toString (Windows.absDir "c:" </> Windows.relDir "tmp" </> Windows.relFile "file.txt") == "c:tmp\\file.txt") :+ {-# LINE 1097 "src/System/Path/Internal.hs" #-}+ ("Windows.toString (Windows.relDir \"dir\" </> Windows.relFile \"file.txt\") == \"dir\\\\file.txt\"",+ Windows.toString (Windows.relDir "dir" </> Windows.relFile "file.txt") == "dir\\file.txt") :+ {-# LINE 1124 "src/System/Path/Internal.hs" #-}+ ("Path.addExtension (relFile \"file.txt\") \"bib\" == Posix.relFile \"file.txt.bib\"",+ Path.addExtension (relFile "file.txt") "bib" == Posix.relFile "file.txt.bib") :+ {-# LINE 1125 "src/System/Path/Internal.hs" #-}+ ("Path.addExtension (relFile \"file.\") \".bib\" == Posix.relFile \"file..bib\"",+ Path.addExtension (relFile "file.") ".bib" == Posix.relFile "file..bib") :+ {-# LINE 1126 "src/System/Path/Internal.hs" #-}+ ("Path.addExtension (relFile \"file\") \".bib\" == Posix.relFile \"file.bib\"",+ Path.addExtension (relFile "file") ".bib" == Posix.relFile "file.bib") :+ {-# LINE 1127 "src/System/Path/Internal.hs" #-}+ ("Path.addExtension Path.emptyFile \"bib\" == Posix.relFile \".bib\"",+ Path.addExtension Path.emptyFile "bib" == Posix.relFile ".bib") :+ {-# LINE 1128 "src/System/Path/Internal.hs" #-}+ ("Path.addExtension Path.emptyFile \".bib\" == Posix.relFile \".bib\"",+ Path.addExtension Path.emptyFile ".bib" == Posix.relFile ".bib") :+ {-# LINE 1129 "src/System/Path/Internal.hs" #-}+ ("Path.takeFileName (Path.addExtension Path.emptyFile \"ext\") == Posix.relFile \".ext\"",+ Path.takeFileName (Path.addExtension Path.emptyFile "ext") == Posix.relFile ".ext") :+ {-# LINE 1144 "src/System/Path/Internal.hs" #-}+ ("Path.dropExtension x == fst (Path.splitExtension x)",+ Path.dropExtension x == fst (Path.splitExtension x)) :+ {-# LINE 1150 "src/System/Path/Internal.hs" #-}+ ("not $ Path.hasAnExtension (Path.dropExtensions x)",+ not $ Path.hasAnExtension (Path.dropExtensions x)) :+ {-# LINE 1161 "src/System/Path/Internal.hs" #-}+ ("Path.replaceExtension (relFile \"file.txt\") \".bob\" == Posix.relFile \"file.bob\"",+ Path.replaceExtension (relFile "file.txt") ".bob" == Posix.relFile "file.bob") :+ {-# LINE 1162 "src/System/Path/Internal.hs" #-}+ ("Path.replaceExtension (relFile \"file.txt\") \"bob\" == Posix.relFile \"file.bob\"",+ Path.replaceExtension (relFile "file.txt") "bob" == Posix.relFile "file.bob") :+ {-# LINE 1163 "src/System/Path/Internal.hs" #-}+ ("Path.replaceExtension (relFile \"file\") \".bob\" == Posix.relFile \"file.bob\"",+ Path.replaceExtension (relFile "file") ".bob" == Posix.relFile "file.bob") :+ {-# LINE 1164 "src/System/Path/Internal.hs" #-}+ ("Path.replaceExtension (relFile \"file.txt\") \"\" == Posix.relFile \"file\"",+ Path.replaceExtension (relFile "file.txt") "" == Posix.relFile "file") :+ {-# LINE 1165 "src/System/Path/Internal.hs" #-}+ ("Path.replaceExtension (relFile \"file.fred.bob\") \"txt\" == Posix.relFile \"file.fred.txt\"",+ Path.replaceExtension (relFile "file.fred.bob") "txt" == Posix.relFile "file.fred.txt") :+ {-# LINE 1182 "src/System/Path/Internal.hs" #-}+ ("uncurry (<.>) (Path.splitExtension x) == x",+ uncurry (<.>) (Path.splitExtension x) == x) :+ {-# LINE 1183 "src/System/Path/Internal.hs" #-}+ ("uncurry Path.addExtension (Path.splitExtension x) == x",+ uncurry Path.addExtension (Path.splitExtension x) == x) :+ {-# LINE 1184 "src/System/Path/Internal.hs" #-}+ ("Path.splitExtension (relFile \"file.txt\") == (Posix.relFile \"file\",\".txt\")",+ Path.splitExtension (relFile "file.txt") == (Posix.relFile "file",".txt")) :+ {-# LINE 1185 "src/System/Path/Internal.hs" #-}+ ("Path.splitExtension (relFile \".bashrc\") == (Posix.emptyFile, \".bashrc\")",+ Path.splitExtension (relFile ".bashrc") == (Posix.emptyFile, ".bashrc")) :+ {-# LINE 1186 "src/System/Path/Internal.hs" #-}+ ("Path.splitExtension (relFile \"file\") == (Posix.relFile \"file\",\"\")",+ Path.splitExtension (relFile "file") == (Posix.relFile "file","")) :+ {-# LINE 1187 "src/System/Path/Internal.hs" #-}+ ("Path.splitExtension (relFile \"file/file.txt\") == (Posix.relFile \"file/file\",\".txt\")",+ Path.splitExtension (relFile "file/file.txt") == (Posix.relFile "file/file",".txt")) :+ {-# LINE 1188 "src/System/Path/Internal.hs" #-}+ ("Path.splitExtension (relFile \"file.txt/boris\") == (Posix.relFile \"file.txt/boris\",\"\")",+ Path.splitExtension (relFile "file.txt/boris") == (Posix.relFile "file.txt/boris","")) :+ {-# LINE 1189 "src/System/Path/Internal.hs" #-}+ ("Path.splitExtension (relFile \"file.txt/boris.ext\") == (Posix.relFile \"file.txt/boris\",\".ext\")",+ Path.splitExtension (relFile "file.txt/boris.ext") == (Posix.relFile "file.txt/boris",".ext")) :+ {-# LINE 1190 "src/System/Path/Internal.hs" #-}+ ("Path.splitExtension (relFile \"file/path.txt.bob.fred\") == (Posix.relFile \"file/path.txt.bob\",\".fred\")",+ Path.splitExtension (relFile "file/path.txt.bob.fred") == (Posix.relFile "file/path.txt.bob",".fred")) :+ {-# LINE 1196 "src/System/Path/Internal.hs" #-}+ ("Path.splitExtensions (relFile \"file.tar.gz\") == (Posix.relFile \"file\",\".tar.gz\")",+ Path.splitExtensions (relFile "file.tar.gz") == (Posix.relFile "file",".tar.gz")) :+ {-# LINE 1212 "src/System/Path/Internal.hs" #-}+ ("Path.takeBaseName (absFile \"/tmp/somedir/myfile.txt\") == Posix.relFile \"myfile\"",+ Path.takeBaseName (absFile "/tmp/somedir/myfile.txt") == Posix.relFile "myfile") :+ {-# LINE 1213 "src/System/Path/Internal.hs" #-}+ ("Path.takeBaseName (relFile \"./myfile.txt\") == Posix.relFile \"myfile\"",+ Path.takeBaseName (relFile "./myfile.txt") == Posix.relFile "myfile") :+ {-# LINE 1214 "src/System/Path/Internal.hs" #-}+ ("Path.takeBaseName (relFile \"myfile.txt\") == Posix.relFile \"myfile\"",+ Path.takeBaseName (relFile "myfile.txt") == Posix.relFile "myfile") :+ {-# LINE 1223 "src/System/Path/Internal.hs" #-}+ ("Path.takeExtension x == snd (Path.splitExtension x)",+ Path.takeExtension x == snd (Path.splitExtension x)) :+ {-# LINE 1224 "src/System/Path/Internal.hs" #-}+ ("Path.takeExtension (Path.addExtension x \"ext\") == \".ext\"",+ Path.takeExtension (Path.addExtension x "ext") == ".ext") :+ {-# LINE 1225 "src/System/Path/Internal.hs" #-}+ ("Path.takeExtension (Path.replaceExtension x \"ext\") == \".ext\"",+ Path.takeExtension (Path.replaceExtension x "ext") == ".ext") :+ {-# LINE 1231 "src/System/Path/Internal.hs" #-}+ ("Path.takeExtensions (Posix.relFile \"file.tar.gz\") == \".tar.gz\"",+ Path.takeExtensions (Posix.relFile "file.tar.gz") == ".tar.gz") :+ {-# LINE 1237 "src/System/Path/Internal.hs" #-}+ ("Path.takeFileName (absFile \"/tmp/somedir/myfile.txt\") == Posix.relFile \"myfile.txt\"",+ Path.takeFileName (absFile "/tmp/somedir/myfile.txt") == Posix.relFile "myfile.txt") :+ {-# LINE 1238 "src/System/Path/Internal.hs" #-}+ ("Path.takeFileName (relFile \"./myfile.txt\") == Posix.relFile \"myfile.txt\"",+ Path.takeFileName (relFile "./myfile.txt") == Posix.relFile "myfile.txt") :+ {-# LINE 1239 "src/System/Path/Internal.hs" #-}+ ("Path.takeFileName (relFile \"myfile.txt\") == Posix.relFile \"myfile.txt\"",+ Path.takeFileName (relFile "myfile.txt") == Posix.relFile "myfile.txt") :+ {-# LINE 1256 "src/System/Path/Internal.hs" #-}+ (" Posix.equalFilePath \"abc/def\" \"abc/def\"",+ Posix.equalFilePath "abc/def" "abc/def") :+ {-# LINE 1257 "src/System/Path/Internal.hs" #-}+ (" Posix.equalFilePath \"abc/def\" \"abc//def\"",+ Posix.equalFilePath "abc/def" "abc//def") :+ {-# LINE 1258 "src/System/Path/Internal.hs" #-} (" Posix.equalFilePath \"/tmp/\" \"/tmp\"", Posix.equalFilePath "/tmp/" "/tmp") :- {-# LINE 801 "src/System/Path/Internal.hs" #-}+ {-# LINE 1259 "src/System/Path/Internal.hs" #-}+ (" Posix.equalFilePath \"/tmp\" \"//tmp\"",+ Posix.equalFilePath "/tmp" "//tmp") :+ {-# LINE 1260 "src/System/Path/Internal.hs" #-}+ (" Posix.equalFilePath \"/tmp\" \"///tmp\"",+ Posix.equalFilePath "/tmp" "///tmp") :+ {-# LINE 1261 "src/System/Path/Internal.hs" #-}+ ("not $ Posix.equalFilePath \"abc\" \"def\"",+ not $ Posix.equalFilePath "abc" "def") :+ {-# LINE 1262 "src/System/Path/Internal.hs" #-} ("not $ Posix.equalFilePath \"/tmp\" \"tmp\"", not $ Posix.equalFilePath "/tmp" "tmp") :- {-# LINE 802 "src/System/Path/Internal.hs" #-}+ {-# LINE 1263 "src/System/Path/Internal.hs" #-}+ (" Windows.equalFilePath \"abc\\\\def\" \"abc\\\\def\"",+ Windows.equalFilePath "abc\\def" "abc\\def") :+ {-# LINE 1264 "src/System/Path/Internal.hs" #-}+ (" Windows.equalFilePath \"abc\\\\def\" \"abc\\\\\\\\def\"",+ Windows.equalFilePath "abc\\def" "abc\\\\def") :+ {-# LINE 1265 "src/System/Path/Internal.hs" #-} (" Windows.equalFilePath \"file\" \"File\"", Windows.equalFilePath "file" "File") :- {-# LINE 803 "src/System/Path/Internal.hs" #-}+ {-# LINE 1266 "src/System/Path/Internal.hs" #-}+ (" Windows.equalFilePath \"\\\\file\" \"\\\\\\\\file\"",+ Windows.equalFilePath "\\file" "\\\\file") :+ {-# LINE 1267 "src/System/Path/Internal.hs" #-}+ (" Windows.equalFilePath \"\\\\file\" \"\\\\\\\\\\\\file\"",+ Windows.equalFilePath "\\file" "\\\\\\file") :+ {-# LINE 1268 "src/System/Path/Internal.hs" #-}+ ("not $ Windows.equalFilePath \"abc\" \"def\"",+ not $ Windows.equalFilePath "abc" "def") :+ {-# LINE 1269 "src/System/Path/Internal.hs" #-} ("not $ Windows.equalFilePath \"file\" \"dir\"", not $ Windows.equalFilePath "file" "dir") :- {-# LINE 817 "src/System/Path/Internal.hs" #-}- ("Posix.joinPath [\"tmp\",\"someDir\",\"dir\"] == Posix.asRelDir \"tmp/someDir/dir\"",- Posix.joinPath ["tmp","someDir","dir"] == Posix.asRelDir "tmp/someDir/dir") :- {-# LINE 818 "src/System/Path/Internal.hs" #-}- ("Posix.joinPath [\"tmp\",\"someDir\",\"file.txt\"] == Posix.asRelFile \"tmp/someDir/file.txt\"",- Posix.joinPath ["tmp","someDir","file.txt"] == Posix.asRelFile "tmp/someDir/file.txt") :- {-# LINE 824 "src/System/Path/Internal.hs" #-}- ("Posix.normalise \"/tmp/fred/./jim/./file\" == Posix.asAbsFile \"/tmp/fred/jim/file\"",- Posix.normalise "/tmp/fred/./jim/./file" == Posix.asAbsFile "/tmp/fred/jim/file") :- {-# LINE 831 "src/System/Path/Internal.hs" #-}- ("Posix.splitPath (Posix.asAbsDir \"/tmp/someDir/mydir.dir\") == (True, [\"tmp\",\"someDir\",\"mydir.dir\"], Nothing)",- Posix.splitPath (Posix.asAbsDir "/tmp/someDir/mydir.dir") == (True, ["tmp","someDir","mydir.dir"], Nothing)) :- {-# LINE 832 "src/System/Path/Internal.hs" #-}- ("Posix.splitPath (Posix.asAbsFile \"/tmp/someDir/myfile.txt\") == (True, [\"tmp\",\"someDir\"], Just \"myfile.txt\")",- Posix.splitPath (Posix.asAbsFile "/tmp/someDir/myfile.txt") == (True, ["tmp","someDir"], Just "myfile.txt")) :- {-# LINE 851 "src/System/Path/Internal.hs" #-}- ("Posix.makeRelative \"/tmp/somedir\" \"/tmp/somedir/anotherdir/file.txt\" == Posix.asRelFile \"anotherdir/file.txt\"",- Posix.makeRelative "/tmp/somedir" "/tmp/somedir/anotherdir/file.txt" == Posix.asRelFile "anotherdir/file.txt") :- {-# LINE 852 "src/System/Path/Internal.hs" #-}- ("Posix.makeRelative \"/tmp/somedir\" \"/tmp/somedir/anotherdir/dir\" == Posix.asRelDir \"anotherdir/dir\"",- Posix.makeRelative "/tmp/somedir" "/tmp/somedir/anotherdir/dir" == Posix.asRelDir "anotherdir/dir") :- {-# LINE 853 "src/System/Path/Internal.hs" #-}- ("Windows.makeRelative \"c:\\\\tmp\\\\somedir\" \"c:\\\\Tmp\\\\SomeDir\\\\AnotherDir\\\\File.txt\" == Windows.asRelFile \"AnotherDir\\\\File.txt\"",- Windows.makeRelative "c:\\tmp\\somedir" "c:\\Tmp\\SomeDir\\AnotherDir\\File.txt" == Windows.asRelFile "AnotherDir\\File.txt") :- {-# LINE 854 "src/System/Path/Internal.hs" #-}- ("Windows.makeRelative \"c:\\\\tmp\\\\somedir\" \"c:\\\\tmp\\\\somedir\\\\anotherdir\\\\dir\" == Windows.asRelDir \"anotherdir\\\\dir\"",- Windows.makeRelative "c:\\tmp\\somedir" "c:\\tmp\\somedir\\anotherdir\\dir" == Windows.asRelDir "anotherdir\\dir") :- {-# LINE 867 "src/System/Path/Internal.hs" #-}- ("Posix.makeAbsolute \"/tmp\" \"file.txt\" == Posix.asAbsFile \"/tmp/file.txt\"",- Posix.makeAbsolute "/tmp" "file.txt" == Posix.asAbsFile "/tmp/file.txt") :- {-# LINE 868 "src/System/Path/Internal.hs" #-}- ("Posix.makeAbsolute \"/tmp\" \"adir/file.txt\" == Posix.asAbsFile \"/tmp/adir/file.txt\"",- Posix.makeAbsolute "/tmp" "adir/file.txt" == Posix.asAbsFile "/tmp/adir/file.txt") :- {-# LINE 869 "src/System/Path/Internal.hs" #-}- ("Posix.makeAbsolute \"/tmp\" \"adir/dir\" == Posix.asAbsDir \"/tmp/adir/dir\"",- Posix.makeAbsolute "/tmp" "adir/dir" == Posix.asAbsDir "/tmp/adir/dir") :- {-# LINE 881 "src/System/Path/Internal.hs" #-}- ("Posix.genericMakeAbsolute \"/tmp\" (Posix.asRelFile \"file.txt\") == \"/tmp/file.txt\"",- Posix.genericMakeAbsolute "/tmp" (Posix.asRelFile "file.txt") == "/tmp/file.txt") :- {-# LINE 882 "src/System/Path/Internal.hs" #-}- ("Posix.genericMakeAbsolute \"/tmp\" (Posix.asRelFile \"adir/file.txt\") == \"/tmp/adir/file.txt\"",- Posix.genericMakeAbsolute "/tmp" (Posix.asRelFile "adir/file.txt") == "/tmp/adir/file.txt") :- {-# LINE 883 "src/System/Path/Internal.hs" #-}- ("Posix.genericMakeAbsolute \"/tmp\" (Posix.asAbsFile \"adir/file.txt\") == \"/adir/file.txt\"",- Posix.genericMakeAbsolute "/tmp" (Posix.asAbsFile "adir/file.txt") == "/adir/file.txt") :- {-# LINE 884 "src/System/Path/Internal.hs" #-}- ("Posix.genericMakeAbsolute \"/tmp\" (Posix.asAbsFile \"/adir/file.txt\") == \"/adir/file.txt\"",- Posix.genericMakeAbsolute "/tmp" (Posix.asAbsFile "/adir/file.txt") == "/adir/file.txt") :- {-# LINE 929 "src/System/Path/Internal.hs" #-}- ("Posix.isAbsolute (Posix.asAbsFile \"fred\")",- Posix.isAbsolute (Posix.asAbsFile "fred")) :- {-# LINE 930 "src/System/Path/Internal.hs" #-}- ("Posix.isAbsolute (Posix.asAbsFile \"/fred\")",- Posix.isAbsolute (Posix.asAbsFile "/fred")) :- {-# LINE 931 "src/System/Path/Internal.hs" #-}- ("Windows.isAbsolute (Windows.asAbsFile \"\\\\fred\")",- Windows.isAbsolute (Windows.asAbsFile "\\fred")) :- {-# LINE 932 "src/System/Path/Internal.hs" #-}- ("Windows.isAbsolute (Windows.asAbsFile \"c:\\\\fred\")",- Windows.isAbsolute (Windows.asAbsFile "c:\\fred")) :- {-# LINE 948 "src/System/Path/Internal.hs" #-}- ("Posix.isRelative (Posix.asRelFile \"fred\")",- Posix.isRelative (Posix.asRelFile "fred")) :- {-# LINE 949 "src/System/Path/Internal.hs" #-}- ("Posix.isRelative (Posix.asRelFile \"/fred\")",- Posix.isRelative (Posix.asRelFile "/fred")) :- {-# LINE 950 "src/System/Path/Internal.hs" #-}- ("Windows.isRelative (Windows.asRelFile \"fred\")",- Windows.isRelative (Windows.asRelFile "fred")) :- {-# LINE 964 "src/System/Path/Internal.hs" #-}- ("null (Posix.takeExtension x) == not (Posix.hasAnExtension x)",- null (Posix.takeExtension x) == not (Posix.hasAnExtension x)) :- {-# LINE 970 "src/System/Path/Internal.hs" #-}- ("Posix.hasExtension \".hs\" (Posix.asRelFile \"MyCode.hs\")",- Posix.hasExtension ".hs" (Posix.asRelFile "MyCode.hs")) :- {-# LINE 971 "src/System/Path/Internal.hs" #-}- ("Posix.hasExtension \".hs\" (Posix.asRelFile \"MyCode.bak.hs\")",- Posix.hasExtension ".hs" (Posix.asRelFile "MyCode.bak.hs")) :- {-# LINE 972 "src/System/Path/Internal.hs" #-}- ("not $ Posix.hasExtension \".hs\" (Posix.asRelFile \"MyCode.hs.bak\")",- not $ Posix.hasExtension ".hs" (Posix.asRelFile "MyCode.hs.bak")) :- {-# LINE 990 "src/System/Path/Internal.hs" #-}+ {-# LINE 1282 "src/System/Path/Internal.hs" #-}+ ("Path.joinPath [\"tmp\",\"someDir\",\"dir\"] == Posix.relDir \"tmp/someDir/dir\"",+ Path.joinPath ["tmp","someDir","dir"] == Posix.relDir "tmp/someDir/dir") :+ {-# LINE 1283 "src/System/Path/Internal.hs" #-}+ ("Path.joinPath [\"tmp\",\"someDir\",\"file.txt\"] == Posix.relFile \"tmp/someDir/file.txt\"",+ Path.joinPath ["tmp","someDir","file.txt"] == Posix.relFile "tmp/someDir/file.txt") :+ {-# LINE 1289 "src/System/Path/Internal.hs" #-}+ ("Path.normalise (absFile \"/tmp/fred/./jim/./file\") == Posix.absFile \"/tmp/fred/jim/file\"",+ Path.normalise (absFile "/tmp/fred/./jim/./file") == Posix.absFile "/tmp/fred/jim/file") :+ {-# LINE 1295 "src/System/Path/Internal.hs" #-}+ ("Path.splitPath (Posix.absDir \"/tmp/someDir/mydir.dir\") == (True, map relDir [\"tmp\",\"someDir\",\"mydir.dir\"], Nothing)",+ Path.splitPath (Posix.absDir "/tmp/someDir/mydir.dir") == (True, map relDir ["tmp","someDir","mydir.dir"], Nothing)) :+ {-# LINE 1296 "src/System/Path/Internal.hs" #-}+ ("Path.splitPath (Posix.absFile \"/tmp/someDir/myfile.txt\") == (True, map relDir [\"tmp\",\"someDir\"], Just $ relFile \"myfile.txt\")",+ Path.splitPath (Posix.absFile "/tmp/someDir/myfile.txt") == (True, map relDir ["tmp","someDir"], Just $ relFile "myfile.txt")) :+ {-# LINE 1315 "src/System/Path/Internal.hs" #-}+ ("Path.makeRelative (absDir \"/tmp/somedir\") (absFile \"/tmp/somedir/anotherdir/file.txt\") == Posix.relFile \"anotherdir/file.txt\"",+ Path.makeRelative (absDir "/tmp/somedir") (absFile "/tmp/somedir/anotherdir/file.txt") == Posix.relFile "anotherdir/file.txt") :+ {-# LINE 1316 "src/System/Path/Internal.hs" #-}+ ("Path.makeRelative (absDir \"/tmp/somedir\") (absDir \"/tmp/somedir/anotherdir/dir\") == Posix.relDir \"anotherdir/dir\"",+ Path.makeRelative (absDir "/tmp/somedir") (absDir "/tmp/somedir/anotherdir/dir") == Posix.relDir "anotherdir/dir") :+ {-# LINE 1317 "src/System/Path/Internal.hs" #-}+ ("Path.makeRelative (absDir \"c:\\\\tmp\\\\somedir\") (absFile \"C:\\\\Tmp\\\\SomeDir\\\\AnotherDir\\\\File.txt\") == Windows.relFile \"AnotherDir\\\\File.txt\"",+ Path.makeRelative (absDir "c:\\tmp\\somedir") (absFile "C:\\Tmp\\SomeDir\\AnotherDir\\File.txt") == Windows.relFile "AnotherDir\\File.txt") :+ {-# LINE 1318 "src/System/Path/Internal.hs" #-}+ ("Path.makeRelative (absDir \"c:\\\\tmp\\\\somedir\") (absDir \"c:\\\\tmp\\\\somedir\\\\anotherdir\\\\dir\") == Windows.relDir \"anotherdir\\\\dir\"",+ Path.makeRelative (absDir "c:\\tmp\\somedir") (absDir "c:\\tmp\\somedir\\anotherdir\\dir") == Windows.relDir "anotherdir\\dir") :+ {-# LINE 1319 "src/System/Path/Internal.hs" #-}+ ("Path.makeRelative (absDir \"c:tmp\\\\somedir\") (absDir \"c:tmp\\\\somedir\\\\anotherdir\\\\dir\") == Windows.relDir \"anotherdir\\\\dir\"",+ Path.makeRelative (absDir "c:tmp\\somedir") (absDir "c:tmp\\somedir\\anotherdir\\dir") == Windows.relDir "anotherdir\\dir") :+ {-# LINE 1330 "src/System/Path/Internal.hs" #-}+ ("Path.makeRelativeMaybe (Posix.absDir \"/tmp/somedir\") (absFile \"/tmp/anotherdir/file.txt\") == Nothing",+ Path.makeRelativeMaybe (Posix.absDir "/tmp/somedir") (absFile "/tmp/anotherdir/file.txt") == Nothing) :+ {-# LINE 1331 "src/System/Path/Internal.hs" #-}+ ("Path.makeRelativeMaybe (Posix.absDir \"/Tmp\") (absFile \"/tmp/anotherdir/file.txt\") == Nothing",+ Path.makeRelativeMaybe (Posix.absDir "/Tmp") (absFile "/tmp/anotherdir/file.txt") == Nothing) :+ {-# LINE 1332 "src/System/Path/Internal.hs" #-}+ ("Path.makeRelativeMaybe (Windows.absDir \"\\\\Tmp\") (absFile \"\\\\tmp\\\\anotherdir\\\\file.txt\") == Just (relFile \"anotherdir\\\\file.txt\")",+ Path.makeRelativeMaybe (Windows.absDir "\\Tmp") (absFile "\\tmp\\anotherdir\\file.txt") == Just (relFile "anotherdir\\file.txt")) :+ {-# LINE 1346 "src/System/Path/Internal.hs" #-}+ ("Path.makeAbsolute (absDir \"/tmp\") (relFile \"file.txt\") == Posix.absFile \"/tmp/file.txt\"",+ Path.makeAbsolute (absDir "/tmp") (relFile "file.txt") == Posix.absFile "/tmp/file.txt") :+ {-# LINE 1347 "src/System/Path/Internal.hs" #-}+ ("Path.makeAbsolute (absDir \"/tmp\") (relFile \"adir/file.txt\") == Posix.absFile \"/tmp/adir/file.txt\"",+ Path.makeAbsolute (absDir "/tmp") (relFile "adir/file.txt") == Posix.absFile "/tmp/adir/file.txt") :+ {-# LINE 1348 "src/System/Path/Internal.hs" #-}+ ("Path.makeAbsolute (absDir \"/tmp\") (relDir \"adir/dir\") == Posix.absDir \"/tmp/adir/dir\"",+ Path.makeAbsolute (absDir "/tmp") (relDir "adir/dir") == Posix.absDir "/tmp/adir/dir") :+ {-# LINE 1370 "src/System/Path/Internal.hs" #-}+ ("Path.genericMakeAbsolute (absDir \"/tmp\") (relFile \"file.txt\") == Posix.absFile \"/tmp/file.txt\"",+ Path.genericMakeAbsolute (absDir "/tmp") (relFile "file.txt") == Posix.absFile "/tmp/file.txt") :+ {-# LINE 1371 "src/System/Path/Internal.hs" #-}+ ("Path.genericMakeAbsolute (absDir \"/tmp\") (relFile \"adir/file.txt\") == Posix.absFile \"/tmp/adir/file.txt\"",+ Path.genericMakeAbsolute (absDir "/tmp") (relFile "adir/file.txt") == Posix.absFile "/tmp/adir/file.txt") :+ {-# LINE 1372 "src/System/Path/Internal.hs" #-}+ ("Path.genericMakeAbsolute (absDir \"/tmp\") (absFile \"/adir/file.txt\") == Posix.absFile \"/adir/file.txt\"",+ Path.genericMakeAbsolute (absDir "/tmp") (absFile "/adir/file.txt") == Posix.absFile "/adir/file.txt") :+ {-# LINE 1457 "src/System/Path/Internal.hs" #-}+ ("Path.isAbsolute (Posix.absFile \"/fred\")",+ Path.isAbsolute (Posix.absFile "/fred")) :+ {-# LINE 1458 "src/System/Path/Internal.hs" #-}+ ("Path.isAbsolute (Windows.absFile \"\\\\fred\")",+ Path.isAbsolute (Windows.absFile "\\fred")) :+ {-# LINE 1459 "src/System/Path/Internal.hs" #-}+ ("Path.isAbsolute (Windows.absFile \"c:\\\\fred\")",+ Path.isAbsolute (Windows.absFile "c:\\fred")) :+ {-# LINE 1460 "src/System/Path/Internal.hs" #-}+ ("Path.isAbsolute (Windows.absFile \"c:fred\")",+ Path.isAbsolute (Windows.absFile "c:fred")) :+ {-# LINE 1467 "src/System/Path/Internal.hs" #-}+ ("Path.isRelative (Posix.relFile \"fred\")",+ Path.isRelative (Posix.relFile "fred")) :+ {-# LINE 1468 "src/System/Path/Internal.hs" #-}+ ("Path.isRelative (Windows.relFile \"fred\")",+ Path.isRelative (Windows.relFile "fred")) :+ {-# LINE 1493 "src/System/Path/Internal.hs" #-}+ ("null (Path.takeExtension x) == not (Path.hasAnExtension x)",+ null (Path.takeExtension x) == not (Path.hasAnExtension x)) :+ {-# LINE 1499 "src/System/Path/Internal.hs" #-}+ ("Path.hasExtension \".hs\" (Posix.relFile \"MyCode.hs\")",+ Path.hasExtension ".hs" (Posix.relFile "MyCode.hs")) :+ {-# LINE 1500 "src/System/Path/Internal.hs" #-}+ ("Path.hasExtension \".hs\" (Posix.relFile \"MyCode.bak.hs\")",+ Path.hasExtension ".hs" (Posix.relFile "MyCode.bak.hs")) :+ {-# LINE 1501 "src/System/Path/Internal.hs" #-}+ ("not $ Path.hasExtension \".hs\" (Posix.relFile \"MyCode.hs.bak\")",+ not $ Path.hasExtension ".hs" (Posix.relFile "MyCode.hs.bak")) :+ {-# LINE 1511 "src/System/Path/Internal.hs" #-} ("Posix.extSeparator == '.'", Posix.extSeparator == '.') :- {-# LINE 1001 "src/System/Path/Internal.hs" #-}- ("Posix.isPathSeparator Posix.pathSeparator",- Posix.isPathSeparator Posix.pathSeparator) :- {-# LINE 1008 "src/System/Path/Internal.hs" #-}- ("Posix.pathSeparator `elem` Posix.pathSeparators",- Posix.pathSeparator `elem` Posix.pathSeparators) :- {-# LINE 1019 "src/System/Path/Internal.hs" #-}+ {-# LINE 1522 "src/System/Path/Internal.hs" #-} ("Posix.isExtSeparator a == (a == Posix.extSeparator)", Posix.isExtSeparator a == (a == Posix.extSeparator)) :- {-# LINE 1026 "src/System/Path/Internal.hs" #-}- ("Posix.isPathSeparator a == (a `elem` Posix.pathSeparators)",- Posix.isPathSeparator a == (a `elem` Posix.pathSeparators)) :- {-# LINE 1032 "src/System/Path/Internal.hs" #-}+ {-# LINE 1528 "src/System/Path/Internal.hs" #-} ("Posix.isSearchPathSeparator a == (a == Posix.searchPathSeparator)", Posix.isSearchPathSeparator a == (a == Posix.searchPathSeparator)) :- {-# LINE 1048 "src/System/Path/Internal.hs" #-}- ("Posix.genericAddExtension \"/\" \"x\" == Posix.asAbsDir \"/.x\"",- Posix.genericAddExtension "/" "x" == Posix.asAbsDir "/.x") :- {-# LINE 1049 "src/System/Path/Internal.hs" #-}- ("Posix.genericAddExtension \"/a\" \"x\" == Posix.asAbsDir \"/a.x\"",- Posix.genericAddExtension "/a" "x" == Posix.asAbsDir "/a.x") :- {-# LINE 1050 "src/System/Path/Internal.hs" #-}- ("Posix.genericAddExtension \"\" \"x\" == Posix.asRelFile \".x\"",- Posix.genericAddExtension "" "x" == Posix.asRelFile ".x") :- {-# LINE 1051 "src/System/Path/Internal.hs" #-}- ("Posix.genericAddExtension \"\" \"\" == Posix.asRelFile \"\"",- Posix.genericAddExtension "" "" == Posix.asRelFile "") :+ {-# LINE 1544 "src/System/Path/Internal.hs" #-}+ ("Path.genericAddExtension (absDir \"/\") \"x\" == Posix.absDir \"/.x\"",+ Path.genericAddExtension (absDir "/") "x" == Posix.absDir "/.x") :+ {-# LINE 1545 "src/System/Path/Internal.hs" #-}+ ("Path.genericAddExtension (absDir \"/a\") \"x\" == Posix.absDir \"/a.x\"",+ Path.genericAddExtension (absDir "/a") "x" == Posix.absDir "/a.x") :+ {-# LINE 1546 "src/System/Path/Internal.hs" #-}+ ("Path.genericAddExtension Path.emptyFile \"x\" == Posix.relFile \".x\"",+ Path.genericAddExtension Path.emptyFile "x" == Posix.relFile ".x") :+ {-# LINE 1547 "src/System/Path/Internal.hs" #-}+ ("Path.genericAddExtension Path.emptyFile \"\" == Posix.emptyFile",+ Path.genericAddExtension Path.emptyFile "" == Posix.emptyFile) :+ {-# LINE 1685 "src/System/Path/Internal.hs" #-}+ ("Posix.isPathSeparator Posix.pathSeparator",+ Posix.isPathSeparator Posix.pathSeparator) :+ {-# LINE 1690 "src/System/Path/Internal.hs" #-}+ ("Posix.pathSeparator `elem` Posix.pathSeparators",+ Posix.pathSeparator `elem` Posix.pathSeparators) :+ {-# LINE 1697 "src/System/Path/Internal.hs" #-}+ ("Posix.isPathSeparator a == (a `elem` Posix.pathSeparators)",+ Posix.isPathSeparator a == (a `elem` Posix.pathSeparators)) : []
test/TestTemplate.hs view
@@ -1,13 +1,15 @@-{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} module TestResult (results) where +import qualified System.Path.Generic as Path import qualified System.Path.Posix as Posix import qualified System.Path.Windows as Windows-import System.Path ((</>), (<.>))+import System.Path.Generic ((</>), (<.>), relFile, relDir, absFile, absDir) import Data.Char (toLower) -results :: (Posix.AbsRelClass ar) => Char -> Posix.FilePath ar -> [(String, Bool)]+results ::+ (Path.AbsRelClass ar) => Char -> Posix.FilePath ar -> [(String, Bool)] results a x = <TESTS_GO_HERE> []
tool/CreateTest.hs view
@@ -1,8 +1,11 @@ module Main where -import Control.Applicative ((<$>))+import qualified Control.Functor.HT as FuncHT+import Control.Applicative ((<$>), (<$)) import Data.List (stripPrefix, isInfixOf) import Data.Maybe (mapMaybe)+import Data.Tuple.HT (mapFst)+import Data.Char (isSpace) import Text.Printf (printf) @@ -20,13 +23,13 @@ main :: IO () main = do- let mapSndF f (a,b) = (,) a <$> f b let readFileNumbered path =- zipWith (\n row -> ((path,n), row)) [(0::Int)..] . lines <$>- readFile path+ zip ((,) path <$> [(0::Int)..]) . lines <$> readFile path testLines <-- mapMaybe (mapSndF $ stripPrefix testPrefix) . concat <$>- mapM readFileNumbered srcfiles+ mapMaybe (FuncHT.mapSnd $ stripPrefix testPrefix) .+ map (\(n,row) -> mapFst ((,) n) $ span isSpace row) .+ concat+ <$> mapM readFileNumbered srcfiles (templateHead,_:templateTail) <- break (tok `isInfixOf`) . lines <$> readFile template {-@@ -34,9 +37,10 @@ such that GHC reports precise source file locations. -} let outLines =- (\((src,n),t) ->- printf " {-# LINE %d \"%s\" #-}\n (%s,\n %s) :"- n src (show t) t) <$> testLines+ (\(((src,n),ind),t) ->+ printf " {-# LINE %d \"%s\" #-}\n (%s,\n%s%s%s) :"+ n src (show t) ind (' ' <$ testPrefix) t)+ <$> testLines writeFile testModule $ unlines $ ("{- Do not edit! Created from " ++ template ++ " -}") :
+ windows/System/Path/Host.hs view
@@ -0,0 +1,2 @@+module System.Path.Host (module System.Path.Windows) where+import System.Path.Windows