29 Commits
0.2.0 ... 0.5.3

Author SHA1 Message Date
Chris Done
28c4f7fe21 Bump to 0.5.3 2015-11-21 19:54:59 +01:00
Chris Done
95fab22567 Merge pull request #7 from mrkkrp/master
Various improvements
2015-11-21 19:53:16 +01:00
mrkkrp
00fabad1f4 Add type-safe synonyms of ‘toFilePath’
This helps to “double check” programmers' assumptions about what kind of
path he is converting into ‘FilePath’. Without these synonyms it's
possible to silently convert wrong type of path into ‘FilePath’.
2015-11-21 16:15:34 +06:00
mrkkrp
733fa04ac3 Write ‘isPrefixOf’ and friends in infix form 2015-11-21 16:14:54 +06:00
mrkkrp
339f7587a3 Remove unused language pragmas 2015-11-21 16:13:52 +06:00
mrkkrp
0476db8ebc Add ‘.stack-work’ to ‘.gitignore’ 2015-11-21 16:12:12 +06:00
Chris Done
57e886b71f Merge pull request #6 from mgsloan/properties-doc-fix
Improve a few property definitions
2015-10-08 09:13:13 -07:00
Michael Sloan
1841d7451c Improve a few property definitions
The properties for stripDir and parent used the name 'parent' as a
variable.

The properties for filename and dirname seemed to be wrong and also used
'parent' as a variable.
2015-10-08 03:00:50 -07:00
Chris Done
62278a77e6 Merge pull request #5 from glasserc/rel-file-tests
test: missing case for parseRelFile
2015-07-09 03:07:35 +02:00
Ethan Glasser-Camp
a4ed4cd504 test: missing case for parseRelFile 2015-07-08 20:28:15 -04:00
Chris Done
c637893aa8 Bump to 0.5.2 2015-06-21 12:19:11 +02:00
Chris Done
09996f1605 Merge pull request #4 from bergmark/no-derivegeneric
Remove unused DeriveGeneric extension, fixes GHC 7.0 build
2015-06-21 12:18:07 +02:00
Adam Bergmark
9f229ecef3 Remove unused DeriveGeneric extension, fixes GHC 7.0 build 2015-06-21 02:29:25 +02:00
Chris Done
44d9e02cc2 Add note in docs about dropTrailingPathSeparator 2015-06-18 08:58:01 +02:00
Chris Done
94a5252ff5 Bump to 0.5.1 2015-06-17 18:45:43 +02:00
Chris Done
df1e191517 Fix syntax error 2015-06-17 18:45:34 +02:00
Chris Done
30890ad3c2 Merge pull request #3 from snoyberg/master
Handle parent directory checks on Windows
2015-06-17 18:43:01 +02:00
Michael Snoyman
9ca83d66b8 Handle parent directory checks on Windows 2015-06-17 19:21:45 +03:00
Chris Done
4e1816392a Fix stripDir p p /= Nothing bug 2015-05-27 17:08:03 +02:00
Chris Done
8f3b169760 Bump to 0.4.0 2015-05-22 11:35:52 +02:00
Chris Done
ffdf4af243 Generalize stripDir to MonadThrow 2015-05-22 11:35:52 +02:00
Chris Done
87a56a93b8 Disallow .. 2015-05-22 11:35:52 +02:00
Chris Done
cb6f472524 Merge pull request #2 from kraai/patch-2
Add source repository information
2015-05-14 17:54:33 +02:00
Chris Done
bff31277e3 Merge pull request #1 from kraai/patch-1
Add ellipsis
2015-05-14 17:48:11 +02:00
kraai
b06a8c9528 Add source repository information 2015-05-14 15:47:04 +00:00
kraai
0c1dd7e493 Add ellipsis 2015-05-14 15:44:41 +00:00
Chris Done
5613ba1dfa Bump for hackage 2015-05-14 08:02:19 +02:00
Chris Done
07aa83ca19 Remove Generic 2015-05-14 08:01:14 +02:00
Chris Done
a68b46b060 Update test suite 2015-05-11 19:01:35 +02:00
6 changed files with 122 additions and 27 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ cabal-dev/
TAGS TAGS
tags tags
*.tag *.tag
.stack-work/

View File

@@ -1,4 +1,20 @@
0.5.3:
* Added conversion functions.
0.2.0: 0.2.0:
* Rename parentAbs to simply parent. * Rename parentAbs to simply parent.
* Add dirname. * Add dirname.
0.3.0:
* Removed Generic instance.
0.4.0:
* Implemented stricter parsing, disabling use of "..".
* Made stripDir generic over MonadThrow
0.5.0:
* Fix stripDir p p /= Nothing bug.
0.5.2:
* Removed unused DeriveGeneric.

View File

@@ -1,5 +1,5 @@
name: path name: path
version: 0.2.0 version: 0.5.3
synopsis: Path synopsis: Path
description: Path description: Path
license: BSD3 license: BSD3
@@ -10,6 +10,7 @@ copyright: 2015 FP Complete
category: Filesystem category: Filesystem
build-type: Simple build-type: Simple
cabal-version: >=1.8 cabal-version: >=1.8
extra-source-files: README.md, CHANGELOG
library library
hs-source-dirs: src/ hs-source-dirs: src/
@@ -29,3 +30,7 @@ test-suite test
, hspec , hspec
, mtl , mtl
, path , path
source-repository head
type: git
location: https://github.com/chrisdone/path.git

View File

@@ -1,5 +1,4 @@
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE EmptyDataDecls #-}
@@ -32,6 +31,10 @@ module Path
,dirname ,dirname
-- * Conversion -- * Conversion
,toFilePath ,toFilePath
,fromAbsDir
,fromRelDir
,fromAbsFile
,fromRelFile
) )
where where
@@ -65,6 +68,7 @@ data PathParseException
| InvalidRelDir FilePath | InvalidRelDir FilePath
| InvalidAbsFile FilePath | InvalidAbsFile FilePath
| InvalidRelFile FilePath | InvalidRelFile FilePath
| Couldn'tStripPrefixDir FilePath FilePath
deriving (Show,Typeable) deriving (Show,Typeable)
instance Exception PathParseException instance Exception PathParseException
@@ -81,7 +85,8 @@ parseAbsDir :: MonadThrow m
parseAbsDir filepath = parseAbsDir filepath =
if FilePath.isAbsolute filepath && if FilePath.isAbsolute filepath &&
not (null (normalizeDir filepath)) && not (null (normalizeDir filepath)) &&
not (isPrefixOf "~/" filepath) not ("~/" `isPrefixOf` filepath) &&
not (hasParentDir filepath)
then return (Path (normalizeDir filepath)) then return (Path (normalizeDir filepath))
else throwM (InvalidAbsDir filepath) else throwM (InvalidAbsDir filepath)
@@ -95,8 +100,10 @@ parseRelDir :: MonadThrow m
parseRelDir filepath = parseRelDir filepath =
if not (FilePath.isAbsolute filepath) && if not (FilePath.isAbsolute filepath) &&
not (null filepath) && not (null filepath) &&
not (isPrefixOf "~/" filepath) && not ("~/" `isPrefixOf` filepath) &&
not (null (normalizeDir filepath)) not (hasParentDir filepath) &&
not (null (normalizeDir filepath)) &&
filepath /= ".."
then return (Path (normalizeDir filepath)) then return (Path (normalizeDir filepath))
else throwM (InvalidRelDir filepath) else throwM (InvalidRelDir filepath)
@@ -109,8 +116,10 @@ parseAbsFile :: MonadThrow m
parseAbsFile filepath = parseAbsFile filepath =
if FilePath.isAbsolute filepath && if FilePath.isAbsolute filepath &&
not (FilePath.hasTrailingPathSeparator filepath) && not (FilePath.hasTrailingPathSeparator filepath) &&
not (isPrefixOf "~/" filepath) && not ("~/" `isPrefixOf` filepath) &&
not (null (normalizeFile filepath)) not (hasParentDir filepath) &&
not (null (normalizeFile filepath)) &&
filepath /= ".."
then return (Path (normalizeFile filepath)) then return (Path (normalizeFile filepath))
else throwM (InvalidAbsFile filepath) else throwM (InvalidAbsFile filepath)
@@ -121,13 +130,29 @@ parseAbsFile filepath =
parseRelFile :: MonadThrow m parseRelFile :: MonadThrow m
=> FilePath -> m (Path Rel File) => FilePath -> m (Path Rel File)
parseRelFile filepath = parseRelFile filepath =
if not (FilePath.isAbsolute filepath || FilePath.hasTrailingPathSeparator filepath) && if not (FilePath.isAbsolute filepath ||
FilePath.hasTrailingPathSeparator filepath) &&
not (null filepath) && not (null filepath) &&
not (isPrefixOf "~/" filepath) && not ("~/" `isPrefixOf` filepath) &&
not (null (normalizeFile filepath)) not (hasParentDir filepath) &&
not (null (normalizeFile filepath)) &&
filepath /= ".."
then return (Path (normalizeFile filepath)) then return (Path (normalizeFile filepath))
else throwM (InvalidRelFile filepath) else throwM (InvalidRelFile filepath)
-- | Helper function: check if the filepath has any parent directories in it.
-- This handles the logic of checking for different path separators on Windows.
hasParentDir :: FilePath -> Bool
hasParentDir filepath' =
("/.." `isSuffixOf` filepath) ||
("/../" `isInfixOf` filepath) ||
("../" `isPrefixOf` filepath)
where
filepath =
case FilePath.pathSeparator of
'/' -> filepath'
x -> map (\y -> if x == y then '/' else y) filepath'
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Constructors -- Constructors
@@ -175,9 +200,29 @@ mkRelFile s =
-- Conversion -- Conversion
-- | Convert to a 'FilePath' type. -- | Convert to a 'FilePath' type.
--
-- All directories have a trailing slash, so if you want no trailing
-- slash, you can use 'System.FilePath.dropTrailingPathSeparator' from
-- the filepath package.
toFilePath :: Path b t -> FilePath toFilePath :: Path b t -> FilePath
toFilePath (Path l) = l toFilePath (Path l) = l
-- | Convert absolute path to directory to 'FilePath' type.
fromAbsDir :: Path Abs Dir -> FilePath
fromAbsDir = toFilePath
-- | Convert relative path to directory to 'FilePath' type.
fromRelDir :: Path Rel Dir -> FilePath
fromRelDir = toFilePath
-- | Convert absolute path to file to 'FilePath' type.
fromAbsFile :: Path Abs File -> FilePath
fromAbsFile = toFilePath
-- | Convert relative path to file to 'FilePath' type.
fromRelFile :: Path Rel File -> FilePath
fromRelFile = toFilePath
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Operations -- Operations
@@ -211,19 +256,25 @@ toFilePath (Path l) = l
-- --
-- The following properties hold: -- The following properties hold:
-- --
-- @stripDir parent (parent \<\/> child) = child@ -- @stripDir x (x \<\/> y) = y@
-- --
-- Cases which are proven not possible: -- Cases which are proven not possible:
-- --
-- @stripDir (a :: Path Abs …) (b :: Path Rel …)@ -- @stripDir (a :: Path Abs …) (b :: Path Rel …)@
-- --
-- @stripDir (a :: Path Rel) (b :: Path Abs …)@ -- @stripDir (a :: Path Rel) (b :: Path Abs …)@
-- --
-- In other words the bases must match. -- In other words the bases must match.
-- --
stripDir :: Path b Dir -> Path b t -> Maybe (Path Rel t) -- Throws: 'Couldn'tStripPrefixDir'
--
stripDir :: MonadThrow m
=> Path b Dir -> Path b t -> m (Path Rel t)
stripDir (Path p) (Path l) = stripDir (Path p) (Path l) =
fmap Path (stripPrefix p l) case stripPrefix p l of
Nothing -> throwM (Couldn'tStripPrefixDir p l)
Just "" -> throwM (Couldn'tStripPrefixDir p l)
Just ok -> return (Path ok)
-- | Is p a parent of the given location? Implemented in terms of -- | Is p a parent of the given location? Implemented in terms of
-- 'stripDir'. The bases must match. -- 'stripDir'. The bases must match.
@@ -235,7 +286,7 @@ isParentOf p l =
-- --
-- The following properties hold: -- The following properties hold:
-- --
-- @parent (parent \<\/> child) == parent@ -- @parent (x \<\/> y) == x@
-- --
-- On the root, getting the parent is idempotent: -- On the root, getting the parent is idempotent:
-- --
@@ -249,7 +300,7 @@ parent (Path fp) =
-- --
-- The following properties hold: -- The following properties hold:
-- --
-- @filename (parent \<\/> filename a) == a@ -- @filename (p \<\/> a) == filename a@
-- --
filename :: Path b File -> Path Rel File filename :: Path b File -> Path Rel File
filename (Path l) = filename (Path l) =
@@ -259,7 +310,7 @@ filename (Path l) =
-- --
-- The following properties hold: -- The following properties hold:
-- --
-- @dirname (parent \<\/> dirname a) == a@ -- @dirname (p \<\/> a) == dirname a@
-- --
dirname :: Path b Dir -> Path Rel Dir dirname :: Path b Dir -> Path Rel Dir
dirname (Path l) = dirname (Path l) =

View File

@@ -1,7 +1,4 @@
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- | Internal types and functions. -- | Internal types and functions.
@@ -10,7 +7,6 @@ module Path.Internal
where where
import Data.Data import Data.Data
import GHC.Generics
-- | Path of some base and type. -- | Path of some base and type.
-- --
@@ -22,7 +18,7 @@ import GHC.Generics
-- All directories end in a trailing separator. There are no duplicate -- All directories end in a trailing separator. There are no duplicate
-- path separators @\/\/@, no @..@, no @.\/@, no @~\/@, etc. -- path separators @\/\/@, no @..@, no @.\/@, no @~\/@, etc.
newtype Path b t = Path FilePath newtype Path b t = Path FilePath
deriving (Typeable,Generic) deriving (Typeable)
-- | String equality. -- | String equality.
-- --

View File

@@ -4,6 +4,9 @@
module Main where module Main where
import Control.Applicative
import Control.Monad
import Data.Maybe
import Data.Monoid import Data.Monoid
import Path import Path
import Path.Internal import Path.Internal
@@ -23,8 +26,27 @@ spec =
describe "Operations: (</>)" operationAppend describe "Operations: (</>)" operationAppend
describe "Operations: stripDir" operationStripDir describe "Operations: stripDir" operationStripDir
describe "Operations: isParentOf" operationIsParentOf describe "Operations: isParentOf" operationIsParentOf
describe "Operations: parentAbs" operationParentAbs describe "Operations: parent" operationParent
describe "Operations: filename" operationFilename describe "Operations: filename" operationFilename
describe "Restrictions" restrictions
-- | Restricting the input of any tricks.
restrictions :: Spec
restrictions =
do parseFails "~/"
parseFails "~/foo"
parseFails "~/foo/bar"
parseFails "../"
parseFails ".."
parseFails "/.."
parseFails "/foo/../bar/"
parseFails "/foo/bar/.."
where parseFails x =
it (show x ++ " should be rejected")
(isNothing (void (parseAbsDir x) <|>
void (parseRelDir x) <|>
void (parseAbsFile x) <|>
void (parseRelFile x)))
-- | The 'filename' operation. -- | The 'filename' operation.
operationFilename :: Spec operationFilename :: Spec
@@ -38,10 +60,10 @@ operationFilename =
filename $(mkRelFile "bar.txt")) == filename $(mkRelFile "bar.txt")) ==
$(mkRelFile "bar.txt")) $(mkRelFile "bar.txt"))
-- | The 'parentAbs' operation. -- | The 'parent' operation.
operationParentAbs :: Spec operationParent :: Spec
operationParentAbs = operationParent =
do it "parentAbs (parent </> child) == parent" do it "parent (parent </> child) == parent"
(parent ($(mkAbsDir "/foo") </> (parent ($(mkAbsDir "/foo") </>
$(mkRelDir "bar")) == $(mkRelDir "bar")) ==
$(mkAbsDir "/foo")) $(mkAbsDir "/foo"))
@@ -79,6 +101,10 @@ operationStripDir =
($(mkRelDir "bar/") </> ($(mkRelDir "bar/") </>
$(mkRelFile "bob/foo.txt")) == $(mkRelFile "bob/foo.txt")) ==
Just $(mkRelFile "bob/foo.txt")) Just $(mkRelFile "bob/foo.txt"))
it "stripDir parent parent = _|_"
(stripDir $(mkAbsDir "/home/chris/foo")
$(mkAbsDir "/home/chris/foo") ==
Nothing)
-- | The '</>' operation. -- | The '</>' operation.
operationAppend :: Spec operationAppend :: Spec