path-io 1.7.0 → 1.8.2
raw patch · 5 files changed
Files
- CHANGELOG.md +17/−0
- Path/IO.hs +116/−74
- Setup.hs +0/−6
- path-io.cabal +21/−22
- tests/Main.hs +27/−14
CHANGELOG.md view
@@ -1,3 +1,20 @@+*Path IO follows [SemVer](https://semver.org/).*++## Path IO 1.8.2++* Maintenance release, compatibility with GHC 9.6, 9.8, and 9.10.++## Path IO 1.8.1++* Fixed a “permission denied” error occurring when `copyDirRecur` is used to+ copy a tree with non-empty read-only directories. [PR+ 82](https://github.com/mrkkrp/path-io/pull/82).++## Path IO 1.8.0++* Added instances of `AnyPath` for `SomeBase`. [PR+ 72](https://github.com/mrkkrp/path-io/pull/72).+ ## Path IO 1.7.0 * Added `doesPathExist`, `getFileSize`, `renamePath`, and
Path/IO.hs view
@@ -126,19 +126,19 @@ import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) import Control.Monad.Trans.Writer.Strict (WriterT, execWriterT, tell)-import qualified Data.DList as DList+import Data.DList qualified as DList import Data.Either (lefts, rights) import Data.Kind (Type) import Data.List ((\\))-import qualified Data.Set as S+import Data.Set qualified as S import Data.Time (UTCTime) import Path-import qualified System.Directory as D-import qualified System.FilePath as F+import System.Directory qualified as D+import System.FilePath qualified as F import System.IO (Handle) import System.IO.Error (isDoesNotExistError)-import qualified System.IO.Temp as T-import qualified System.PosixCompat.Files as P+import System.IO.Temp qualified as T+import System.PosixCompat.Files qualified as P ---------------------------------------------------------------------------- -- Actions on directories@@ -175,14 +175,14 @@ -- * 'InappropriateType' -- The path refers to an existing non-directory object. -- @[EEXIST]@-createDir :: MonadIO m => Path b Dir -> m ()+createDir :: (MonadIO m) => Path b Dir -> m () createDir = liftD D.createDirectory -- | @'createDirIfMissing' parents dir@ creates a new directory @dir@ if it -- doesn't exist. If the first argument is 'True' the function will also -- create all parent directories if they are missing. createDirIfMissing ::- MonadIO m =>+ (MonadIO m) => -- | Create its parents too? Bool -> -- | The path to the directory you want to make@@ -196,7 +196,7 @@ -- > ensureDir = createDirIfMissing True -- -- @since 0.3.1-ensureDir :: MonadIO m => Path b Dir -> m ()+ensureDir :: (MonadIO m) => Path b Dir -> m () ensureDir = createDirIfMissing True -- | @'removeDir' dir@ removes an existing directory @dir@. The@@ -236,13 +236,13 @@ -- * 'InappropriateType' -- The operand refers to an existing non-directory object. -- @[ENOTDIR]@-removeDir :: MonadIO m => Path b Dir -> m ()+removeDir :: (MonadIO m) => Path b Dir -> m () removeDir = liftD D.removeDirectory -- | @'removeDirRecur' dir@ removes an existing directory @dir@ together -- with its contents and sub-directories. Within this directory, symbolic -- links are removed without affecting their targets.-removeDirRecur :: MonadIO m => Path b Dir -> m ()+removeDirRecur :: (MonadIO m) => Path b Dir -> m () removeDirRecur = liftD D.removeDirectoryRecursive -- | Remove a file or directory at /path/ together with its contents and@@ -263,7 +263,7 @@ -- exception. The first exception that it encountered is re-thrown. -- -- @since 1.7.0-removePathForcibly :: MonadIO m => Path b t -> m ()+removePathForcibly :: (MonadIO m) => Path b t -> m () removePathForcibly = liftD D.removePathForcibly -- | @'renameDir' old new@ changes the name of an existing directory from@@ -312,7 +312,7 @@ -- Either path refers to an existing non-directory object. -- @[ENOTDIR, EISDIR]@ renameDir ::- MonadIO m =>+ (MonadIO m) => -- | Old name Path b0 Dir -> -- | New name@@ -362,7 +362,7 @@ -- @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@ -- -- @since 1.7.0-renamePath :: MonadIO m => Path b0 t -> Path b1 t -> m ()+renamePath :: (MonadIO m) => Path b0 t -> Path b1 t -> m () renamePath = liftD2 D.renamePath -- | @'listDir' dir@ returns a list of /all/ entries in @dir@ without the@@ -394,7 +394,7 @@ -- The path refers to an existing non-directory object. -- @[ENOTDIR]@ listDir ::- MonadIO m =>+ (MonadIO m) => -- | Directory to list Path b Dir -> -- | Sub-directories and files@@ -411,7 +411,7 @@ -- -- @since 1.4.0 listDirRel ::- MonadIO m =>+ (MonadIO m) => -- | Directory to list Path b Dir -> -- | Sub-directories and files@@ -431,7 +431,7 @@ -- -- __Note__: before version /1.3.0/, this function followed symlinks. listDirRecur ::- MonadIO m =>+ (MonadIO m) => -- | Directory to list Path b Dir -> -- | Sub-directories and files@@ -453,7 +453,7 @@ -- -- @since 1.4.2 listDirRecurRel ::- MonadIO m =>+ (MonadIO m) => -- | Directory to list Path b Dir -> -- | Sub-directories and files@@ -487,7 +487,7 @@ -- traversing symlinked directories, but recreating symlinks in the target -- directory according to their targets in the source directory. copyDirRecur ::- (MonadIO m, MonadCatch m) =>+ (MonadIO m) => -- | Source Path b0 Dir -> -- | Destination@@ -512,7 +512,7 @@ -- traversing symlinked directories, but recreating symlinks in the target -- directory according to their targets in the source directory. copyDirRecur' ::- (MonadIO m, MonadCatch m) =>+ (MonadIO m) => -- | Source Path b0 Dir -> -- | Destination@@ -524,7 +524,7 @@ -- to preserve directory permissions or not. /Does not/ follow symbolic -- links. Internal function. copyDirRecurGen ::- MonadIO m =>+ (MonadIO m) => -- | Should we preserve directory permissions? Bool -> -- | Source@@ -545,7 +545,7 @@ (new </>) <$> stripProperPrefix old path ensureDir bdest- forM_ dirs $ \srcDir -> do+ copyPermissionsIOs <- forM dirs $ \srcDir -> do destDir <- swapParent bsrc bdest srcDir dirIsSymlink <- isSymlink srcDir if dirIsSymlink@@ -554,8 +554,7 @@ D.createDirectoryLink target $ toFilePath' destDir else ensureDir destDir- when preserveDirPermissions $- ignoringIOErrors (copyPermissions srcDir destDir)+ pure $ ignoringIOErrors (copyPermissions srcDir destDir) forM_ files $ \srcFile -> do destFile <- swapParent bsrc bdest srcFile fileIsSymlink <- isSymlink srcFile@@ -564,8 +563,9 @@ target <- getSymlinkTarget srcFile D.createFileLink target (toFilePath destFile) else copyFile srcFile destFile- when preserveDirPermissions $+ when preserveDirPermissions $ do ignoringIOErrors (copyPermissions bsrc bdest)+ sequence_ copyPermissionsIOs ---------------------------------------------------------------------------- -- Walking directory trees@@ -626,7 +626,7 @@ -- -- @since 1.2.0 walkDir ::- MonadIO m =>+ (MonadIO m) => -- | Handler (@dir -> subdirs -> files -> 'WalkAction'@) (Path Abs Dir -> [Path Abs Dir] -> [Path Abs File] -> m (WalkAction Abs)) -> -- | Directory where traversal begins@@ -668,7 +668,7 @@ -- -- @since 1.4.2 walkDirRel ::- MonadIO m =>+ (MonadIO m) => -- | Handler (@dir -> subdirs -> files -> 'WalkAction'@) ( Path Rel Dir -> [Path Rel Dir] ->@@ -809,7 +809,7 @@ -- -- * 'UnsupportedOperation' -- The operating system has no notion of current working directory.-getCurrentDir :: MonadIO m => m (Path Abs Dir)+getCurrentDir :: (MonadIO m) => m (Path Abs Dir) getCurrentDir = liftIO $ D.getCurrentDirectory >>= parseAbsDir -- | Change the working directory to the given path.@@ -844,7 +844,7 @@ -- * 'InappropriateType' -- The path refers to an existing non-directory object. -- @[ENOTDIR]@-setCurrentDir :: MonadIO m => Path b Dir -> m ()+setCurrentDir :: (MonadIO m) => Path b Dir -> m () setCurrentDir = liftD D.setCurrentDirectory -- | Run an 'IO' action with the given working directory and restore the@@ -884,7 +884,7 @@ -- * 'isDoesNotExistError' -- The home directory for the current user does not exist, or -- cannot be found.-getHomeDir :: MonadIO m => m (Path Abs Dir)+getHomeDir :: (MonadIO m) => m (Path Abs Dir) getHomeDir = liftIO D.getHomeDirectory >>= resolveDir' -- | Obtain the path to a special directory for storing user-specific@@ -911,7 +911,7 @@ -- The home directory for the current user does not exist, or cannot be -- found. getAppUserDataDir ::- MonadIO m =>+ (MonadIO m) => -- | Name of application (used in path construction) String -> m (Path Abs Dir)@@ -935,7 +935,7 @@ -- * 'isDoesNotExistError' -- The document directory for the current user does not exist, or -- cannot be found.-getUserDocsDir :: MonadIO m => m (Path Abs Dir)+getUserDocsDir :: (MonadIO m) => m (Path Abs Dir) getUserDocsDir = liftIO $ D.getUserDocumentsDirectory >>= parseAbsDir -- | Return the current directory for temporary files.@@ -963,7 +963,7 @@ -- The operating system has no notion of temporary directory. -- -- The function doesn't verify whether the path exists.-getTempDir :: MonadIO m => m (Path Abs Dir)+getTempDir :: (MonadIO m) => m (Path Abs Dir) getTempDir = liftIO D.getTemporaryDirectory >>= resolveDir' -- | Obtain the paths to special directories for storing user-specific@@ -983,7 +983,7 @@ -- -- @since 1.2.1 getXdgDir ::- MonadIO m =>+ (MonadIO m) => -- | Which special directory D.XdgDirectory -> -- | A relative path that is appended to the path; if 'Nothing', the@@ -1003,7 +1003,7 @@ -- -- @since 1.5.0 getXdgDirList ::- MonadIO m =>+ (MonadIO m) => -- | Which special directory list D.XdgDirectoryList -> m [Path Abs Dir]@@ -1051,7 +1051,7 @@ -- Please note that before version 1.2.3.0 of the @directory@ package, -- this function had unpredictable behavior on non-existent paths. canonicalizePath ::- MonadIO m =>+ (MonadIO m) => path -> m (AbsPath path) @@ -1061,7 +1061,7 @@ -- If the path is already absolute, the operation never fails. Otherwise, -- the operation may fail with the same exceptions as 'getCurrentDir'. makeAbsolute ::- MonadIO m =>+ (MonadIO m) => path -> m (AbsPath path) @@ -1069,7 +1069,7 @@ -- -- @since 0.3.0 makeRelative ::- MonadThrow m =>+ (MonadThrow m) => -- | Base directory Path Abs Dir -> -- | Path that will be made relative to base directory@@ -1080,7 +1080,7 @@ -- -- @since 0.3.0 makeRelativeToCurrentDir ::- MonadIO m =>+ (MonadIO m) => path -> m (RelPath path) @@ -1102,12 +1102,54 @@ makeRelative b p = parseRelDir (F.makeRelative (toFilePath b) (toFilePath p)) makeRelativeToCurrentDir p = liftIO $ getCurrentDir >>= flip makeRelative p +-- | @since 1.8.0+instance AnyPath (SomeBase File) where+ type AbsPath (SomeBase File) = Path Abs File+ type RelPath (SomeBase File) = Path Rel File++ canonicalizePath s = case s of+ Abs a -> canonicalizePath a+ Rel a -> canonicalizePath a++ makeAbsolute s = case s of+ Abs a -> makeAbsolute a+ Rel a -> makeAbsolute a++ makeRelative r s = case s of+ Abs a -> makeRelative r a+ Rel a -> makeRelative r a++ makeRelativeToCurrentDir s = case s of+ Abs a -> makeRelativeToCurrentDir a+ Rel a -> makeRelativeToCurrentDir a++-- | @since 1.8.0+instance AnyPath (SomeBase Dir) where+ type AbsPath (SomeBase Dir) = Path Abs Dir+ type RelPath (SomeBase Dir) = Path Rel Dir++ canonicalizePath s = case s of+ Abs a -> canonicalizePath a+ Rel a -> canonicalizePath a++ makeAbsolute s = case s of+ Abs a -> makeAbsolute a+ Rel a -> makeAbsolute a++ makeRelative r s = case s of+ Abs a -> makeRelative r a+ Rel a -> makeRelative r a++ makeRelativeToCurrentDir s = case s of+ Abs a -> makeRelativeToCurrentDir a+ Rel a -> makeRelativeToCurrentDir a+ -- | Append stringly-typed path to an absolute path and then canonicalize -- it. -- -- @since 0.3.0 resolveFile ::- MonadIO m =>+ (MonadIO m) => -- | Base directory Path Abs Dir -> -- | Path to resolve@@ -1119,7 +1161,7 @@ -- -- @since 0.3.0 resolveFile' ::- MonadIO m =>+ (MonadIO m) => -- | Path to resolve FilePath -> m (Path Abs File)@@ -1129,7 +1171,7 @@ -- -- @since 0.3.0 resolveDir ::- MonadIO m =>+ (MonadIO m) => -- | Base directory Path Abs Dir -> -- | Path to resolve@@ -1141,7 +1183,7 @@ -- -- @since 0.3.0 resolveDir' ::- MonadIO m =>+ (MonadIO m) => -- | Path to resolve FilePath -> m (Path Abs Dir)@@ -1180,7 +1222,7 @@ -- * 'InappropriateType' -- The operand refers to an existing directory. -- @[EPERM, EINVAL]@-removeFile :: MonadIO m => Path b File -> m ()+removeFile :: (MonadIO m) => Path b File -> m () removeFile = liftD D.removeFile -- | @'renameFile' old new@ changes the name of an existing file system@@ -1224,7 +1266,7 @@ -- Either path refers to an existing directory. -- @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@ renameFile ::- MonadIO m =>+ (MonadIO m) => -- | Original location Path b0 File -> -- | New location@@ -1237,7 +1279,7 @@ -- file. Neither path may refer to an existing directory. The permissions of -- @old@ are copied to @new@, if possible. copyFile ::- MonadIO m =>+ (MonadIO m) => -- | Original location Path b0 File -> -- | Where to put copy@@ -1248,7 +1290,7 @@ -- | Obtain the size of a file in bytes. -- -- @since 1.7.0-getFileSize :: MonadIO m => Path b File -> m Integer+getFileSize :: (MonadIO m) => Path b File -> m Integer getFileSize = liftD D.getFileSize -- | Given an executable file name, search for such file in the directories@@ -1266,7 +1308,7 @@ -- the directory containing the current executable. See -- <http://msdn.microsoft.com/en-us/library/aa365527.aspx> for more details. findExecutable ::- MonadIO m =>+ (MonadIO m) => -- | Executable file name Path Rel File -> -- | Path to found executable@@ -1275,7 +1317,7 @@ -- | Search through the given set of directories for the given file. findFile ::- MonadIO m =>+ (MonadIO m) => -- | Set of directories to search in [Path b Dir] -> -- | Filename of interest@@ -1293,7 +1335,7 @@ -- | Search through the given set of directories for the given file and -- return a list of paths where the given file exists. findFiles ::- MonadIO m =>+ (MonadIO m) => -- | Set of directories to search in [Path b Dir] -> -- | Filename of interest@@ -1306,7 +1348,7 @@ -- the given property (usually permissions) and return a list of paths where -- the given file exists and has the property. findFilesWith ::- MonadIO m =>+ (MonadIO m) => -- | How to test the files (Path Abs File -> m Bool) -> -- | Set of directories to search in@@ -1355,7 +1397,7 @@ -- -- @since 1.5.0 createFileLink ::- MonadIO m =>+ (MonadIO m) => -- | Path to the target file Path b0 File -> -- | Path to the link to be created@@ -1392,7 +1434,7 @@ -- -- @since 1.5.0 createDirLink ::- MonadIO m =>+ (MonadIO m) => -- | Path to the target directory Path b0 Dir -> -- | Path to the link to be created@@ -1412,7 +1454,7 @@ -- -- @since 1.5.0 removeDirLink ::- MonadIO m =>+ (MonadIO m) => -- | Path to the link to be removed Path b Dir -> m ()@@ -1431,7 +1473,7 @@ -- -- @since 1.5.0 getSymlinkTarget ::- MonadIO m =>+ (MonadIO m) => -- | Symlink path Path b t -> m FilePath@@ -1449,7 +1491,7 @@ -- | Check if the given path is a symbolic link. -- -- @since 1.3.0-isSymlink :: MonadIO m => Path b t -> m Bool+isSymlink :: (MonadIO m) => Path b t -> m Bool isSymlink = liftD D.pathIsSymbolicLink ----------------------------------------------------------------------------@@ -1547,7 +1589,7 @@ -- -- @since 0.2.0 openTempFile ::- MonadIO m =>+ (MonadIO m) => -- | Directory to create file in Path b Dir -> -- | File name template; if the template is "foo.ext" then the created@@ -1570,7 +1612,7 @@ -- -- @since 0.2.0 openBinaryTempFile ::- MonadIO m =>+ (MonadIO m) => -- | Directory to create file in Path b Dir -> -- | File name template, see 'openTempFile'@@ -1590,7 +1632,7 @@ -- -- @since 0.2.0 createTempDir ::- MonadIO m =>+ (MonadIO m) => -- | Directory to create file in Path b Dir -> -- | Directory name template, see 'openTempFile'@@ -1610,22 +1652,22 @@ -- this function may return false even if the file does actually exist. -- -- @since 1.7.0-doesPathExist :: MonadIO m => Path b t -> m Bool+doesPathExist :: (MonadIO m) => Path b t -> m Bool doesPathExist = liftD D.doesPathExist -- | The operation 'doesFileExist' returns 'True' if the argument file -- exists and is not a directory, and 'False' otherwise.-doesFileExist :: MonadIO m => Path b File -> m Bool+doesFileExist :: (MonadIO m) => Path b File -> m Bool doesFileExist = liftD D.doesFileExist -- | The operation 'doesDirExist' returns 'True' if the argument file exists -- and is either a directory or a symbolic link to a directory, and 'False' -- otherwise.-doesDirExist :: MonadIO m => Path b Dir -> m Bool+doesDirExist :: (MonadIO m) => Path b Dir -> m Bool doesDirExist = liftD D.doesDirectoryExist -- | Check if there is a file or directory on specified path.-isLocationOccupied :: MonadIO m => Path b t -> m Bool+isLocationOccupied :: (MonadIO m) => Path b t -> m Bool isLocationOccupied path = do let fp = toFilePath path file <- liftIO (D.doesFileExist fp)@@ -1662,7 +1704,7 @@ -- the permissions; or -- -- * 'isDoesNotExistError' if the file or directory does not exist.-getPermissions :: MonadIO m => Path b t -> m D.Permissions+getPermissions :: (MonadIO m) => Path b t -> m D.Permissions getPermissions = liftD D.getPermissions -- | The 'setPermissions' operation sets the permissions for the file or@@ -1674,13 +1716,13 @@ -- the permissions; or -- -- * 'isDoesNotExistError' if the file or directory does not exist.-setPermissions :: MonadIO m => Path b t -> D.Permissions -> m ()+setPermissions :: (MonadIO m) => Path b t -> D.Permissions -> m () setPermissions = liftD2' D.setPermissions -- | Set permissions for the object found on second given path so they match -- permissions of the object on the first path. copyPermissions ::- MonadIO m =>+ (MonadIO m) => -- | From where to copy Path b0 t0 -> -- | What to modify@@ -1706,7 +1748,7 @@ -- -- Note: this is a piece of conditional API, only available if -- @directory-1.2.3.0@ or later is used.-getAccessTime :: MonadIO m => Path b t -> m UTCTime+getAccessTime :: (MonadIO m) => Path b t -> m UTCTime getAccessTime = liftD D.getAccessTime -- | Change the time at which the file or directory was last accessed.@@ -1733,7 +1775,7 @@ -- -- Note: this is a piece of conditional API, only available if -- @directory-1.2.3.0@ or later is used.-setAccessTime :: MonadIO m => Path b t -> UTCTime -> m ()+setAccessTime :: (MonadIO m) => Path b t -> UTCTime -> m () setAccessTime = liftD2' D.setAccessTime -- | Change the time at which the file or directory was last modified.@@ -1760,7 +1802,7 @@ -- -- Note: this is a piece of conditional API, only available if -- @directory-1.2.3.0@ or later is used.-setModificationTime :: MonadIO m => Path b t -> UTCTime -> m ()+setModificationTime :: (MonadIO m) => Path b t -> UTCTime -> m () setModificationTime = liftD2' D.setModificationTime -- | Obtain the time at which the file or directory was last modified.@@ -1775,7 +1817,7 @@ -- Caveat for POSIX systems: This function returns a timestamp with -- sub-second resolution only if this package is compiled against -- @unix-2.6.0.0@ or later and the underlying filesystem supports them.-getModificationTime :: MonadIO m => Path b t -> m UTCTime+getModificationTime :: (MonadIO m) => Path b t -> m UTCTime getModificationTime = liftD D.getModificationTime ----------------------------------------------------------------------------@@ -1784,7 +1826,7 @@ -- | Lift an action in 'IO' that takes 'FilePath' into an action in slightly -- more abstract monad that takes 'Path'. liftD ::- MonadIO m =>+ (MonadIO m) => -- | Original action (FilePath -> IO a) -> -- | 'Path' argument@@ -1796,7 +1838,7 @@ -- | Similar to 'liftD' but for functions with arity 2. liftD2 ::- MonadIO m =>+ (MonadIO m) => -- | Original action (FilePath -> FilePath -> IO a) -> -- | First 'Path' argument@@ -1810,7 +1852,7 @@ -- | Similar to 'liftD2', but allows us to pass second argument of arbitrary -- type. liftD2' ::- MonadIO m =>+ (MonadIO m) => -- | Original action (FilePath -> v -> IO a) -> -- | First 'Path' argument@@ -1829,5 +1871,5 @@ ignoringIOErrors :: IO () -> IO () ignoringIOErrors ioe = ioe `catch` handler where- handler :: Monad m => IOError -> m ()+ handler :: (Monad m) => IOError -> m () handler = const (return ())
− Setup.hs
@@ -1,6 +0,0 @@-module Main (main) where--import Distribution.Simple--main :: IO ()-main = defaultMain
path-io.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.4 name: path-io-version: 1.7.0+version: 1.8.2 license: BSD-3-Clause license-file: LICENSE.md maintainer: Mark Karpov <markkarpov92@gmail.com> author: Mark Karpov <markkarpov92@gmail.com>-tested-with: ghc ==8.10.7 ghc ==9.0.2 ghc ==9.2.1+tested-with: ghc ==9.6.5 ghc ==9.8.2 ghc ==9.10.1 homepage: https://github.com/mrkkrp/path-io bug-reports: https://github.com/mrkkrp/path-io/issues synopsis: Interface to ‘directory’ package for users of ‘path’@@ -27,49 +27,48 @@ library exposed-modules: Path.IO- default-language: Haskell2010+ default-language: GHC2021 build-depends:- base >=4.13 && <5.0,+ base >=4.15 && <5, containers, directory >=1.3.2.0 && <1.4,- dlist >=0.8 && <2.0,+ dlist >=0.8 && <2, exceptions >=0.8 && <0.11,- filepath >=1.2 && <1.5,- path >=0.6 && <0.10,+ filepath >=1.2 && <1.6,+ path >=0.7.1 && <0.10, temporary >=1.1 && <1.4,- time >=1.4 && <1.13,+ time >=1.4 && <1.15, transformers >=0.3 && <0.7, unix-compat if flag(dev)- ghc-options: -Wall -Werror+ ghc-options:+ -Wall -Werror -Wredundant-constraints -Wpartial-fields+ -Wunused-packages else ghc-options: -O2 -Wall - if flag(dev)- ghc-options:- -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns- -Wnoncanonical-monad-instances- test-suite tests type: exitcode-stdio-1.0 main-is: Main.hs hs-source-dirs: tests- default-language: Haskell2010+ default-language: GHC2021 build-depends:- base >=4.13 && <5.0,- directory >=1.3.2.0 && <1.4,+ base >=4.15 && <5, exceptions >=0.8 && <0.11,- hspec >=2.0 && <3.0,- filepath >=1.2 && <1.5,- path >=0.6 && <0.10,+ hspec >=2 && <3,+ path >=0.7.1 && <0.10, path-io,- transformers >=0.3 && <0.7, unix-compat if flag(dev)- ghc-options: -Wall -Werror+ ghc-options:+ -Wall -Werror -Wredundant-constraints -Wpartial-fields+ -Wunused-packages else ghc-options: -O2 -Wall++ if impl(ghc >=9.8)+ ghc-options: -Wno-x-partial
tests/Main.hs view
@@ -166,7 +166,7 @@ -- | Follows symbolic links. listDirRecurCyclic ::- (MonadIO m, MonadThrow m) =>+ (MonadIO m) => -- | Directory to list Path b Dir -> -- | Sub-directories and files@@ -274,12 +274,21 @@ pdir = root </> $(mkRelDir "pdir") withinSandbox = (pdir </>) ensureDir pdir- ensureDir $ withinSandbox $(mkRelDir "b")+ let b = withinSandbox $(mkRelDir "b")+ ensureDir b ensureDir $ withinSandbox $(mkRelDir "b/c")- -- to verify that we do not follow symbolic links. We should not list b's- -- tree under 'a'.+ -- Create a read-only directory with a file inside to test that the code+ -- that copies directory permissions can handle that gracefully.+ --+ -- See: https://github.com/mrkkrp/path-io/pull/82+ let readonlyDir = withinSandbox $(mkRelDir "readonly-dir")+ ensureDir readonlyDir+ -- We should not list b's tree under 'a' in order to verify that we do not+ -- follow symbolic links. createSymbolicLink "b" (toFilePath $ withinSandbox $(mkRelFile "a")) forM_ files $ (`writeFile` "") . toFilePath . withinSandbox+ getPermissions readonlyDir+ >>= setPermissions readonlyDir . setOwnerWritable False return pdir -- | Get the inner structure of a directory. Items are sorted, so it's@@ -312,11 +321,13 @@ populatedDirStructure = ( [ $(mkRelDir "a"), $(mkRelDir "b"),- $(mkRelDir "b/c")+ $(mkRelDir "b/c"),+ $(mkRelDir "readonly-dir") ], [ $(mkRelFile "b/c/three.txt"), $(mkRelFile "b/two.txt"),- $(mkRelFile "one.txt")+ $(mkRelFile "one.txt"),+ $(mkRelFile "readonly-dir/two.txt") ] ) @@ -359,26 +370,28 @@ createSymbolicLink "../../e" (toFilePath $ withinSandbox $(mkRelFile "e/f/g")) return pdir --- | Top-level structure of populated directory as it should be scanned by--- the 'listDir' function.+-- | Top-level structure of the populated directory as it should be scanned+-- by the 'listDir' function. populatedDirTop :: ([Path Rel Dir], [Path Rel File]) populatedDirTop = ( [ $(mkRelDir "a"),- $(mkRelDir "b")+ $(mkRelDir "b"),+ $(mkRelDir "readonly-dir") ], [ $(mkRelFile "one.txt") ] ) --- | Structure of populated directory as it should be scanned by--- 'listDirRecurWith' function using predicates to filter out dir 'c' and the--- file 'two.txt'+-- | Structure of the populated directory as it should be scanned by+-- 'listDirRecurWith' function using predicates to filter out dir 'c' and+-- the file @two.txt@. populatedDirRecurWith :: ([Path Rel Dir], [Path Rel File]) populatedDirRecurWith = ( [ $(mkRelDir "a"),- $(mkRelDir "b")+ $(mkRelDir "b"),+ $(mkRelDir "readonly-dir") ],- [ $(mkRelFile "a/c/three.txt"), -- via symbolic link+ [ $(mkRelFile "a/c/three.txt"), -- via a symbolic link $(mkRelFile "b/c/three.txt"), $(mkRelFile "one.txt") ]