Compare commits
2 Commits
master
...
constructo
Author | SHA1 | Date | |
---|---|---|---|
29923d1023 | |||
c3c96ed371 |
124
src/Path.hs
124
src/Path.hs
@ -18,8 +18,6 @@ module Path
|
|||||||
Path
|
Path
|
||||||
,Abs
|
,Abs
|
||||||
,Rel
|
,Rel
|
||||||
,File
|
|
||||||
,Dir
|
|
||||||
-- * Parsing
|
-- * Parsing
|
||||||
,parseAbsDir
|
,parseAbsDir
|
||||||
,parseRelDir
|
,parseRelDir
|
||||||
@ -37,13 +35,8 @@ module Path
|
|||||||
,isParentOf
|
,isParentOf
|
||||||
,parent
|
,parent
|
||||||
,filename
|
,filename
|
||||||
,dirname
|
|
||||||
-- * Conversion
|
-- * Conversion
|
||||||
,toFilePath
|
,toFilePath
|
||||||
,fromAbsDir
|
|
||||||
,fromRelDir
|
|
||||||
,fromAbsFile
|
|
||||||
,fromRelFile
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@ -65,11 +58,6 @@ data Abs deriving (Typeable)
|
|||||||
-- | A relative path; one without a root.
|
-- | A relative path; one without a root.
|
||||||
data Rel deriving (Typeable)
|
data Rel deriving (Typeable)
|
||||||
|
|
||||||
-- | A file path.
|
|
||||||
data File deriving (Typeable)
|
|
||||||
|
|
||||||
-- | A directory path.
|
|
||||||
data Dir deriving (Typeable)
|
|
||||||
|
|
||||||
-- | Exception when parsing a location.
|
-- | Exception when parsing a location.
|
||||||
data PathParseException
|
data PathParseException
|
||||||
@ -78,6 +66,7 @@ data PathParseException
|
|||||||
| InvalidAbsFile FilePath
|
| InvalidAbsFile FilePath
|
||||||
| InvalidRelFile FilePath
|
| InvalidRelFile FilePath
|
||||||
| Couldn'tStripPrefixDir FilePath FilePath
|
| Couldn'tStripPrefixDir FilePath FilePath
|
||||||
|
| InvalidTypeCombination
|
||||||
deriving (Show,Typeable)
|
deriving (Show,Typeable)
|
||||||
instance Exception PathParseException
|
instance Exception PathParseException
|
||||||
|
|
||||||
@ -90,14 +79,14 @@ instance Exception PathParseException
|
|||||||
-- Throws: 'PathParseException'
|
-- Throws: 'PathParseException'
|
||||||
--
|
--
|
||||||
parseAbsDir :: MonadThrow m
|
parseAbsDir :: MonadThrow m
|
||||||
=> FilePath -> m (Path Abs Dir)
|
=> FilePath -> m (Path Abs)
|
||||||
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) &&
|
not (hasParentDir filepath) &&
|
||||||
FilePath.isValid filepath
|
FilePath.isValid filepath
|
||||||
then return (Path (normalizeDir filepath))
|
then return (DPath (normalizeDir filepath))
|
||||||
else throwM (InvalidAbsDir filepath)
|
else throwM (InvalidAbsDir filepath)
|
||||||
|
|
||||||
-- | Get a location for a relative directory. Produces a normalized
|
-- | Get a location for a relative directory. Produces a normalized
|
||||||
@ -108,7 +97,7 @@ parseAbsDir filepath =
|
|||||||
-- Throws: 'PathParseException'
|
-- Throws: 'PathParseException'
|
||||||
--
|
--
|
||||||
parseRelDir :: MonadThrow m
|
parseRelDir :: MonadThrow m
|
||||||
=> FilePath -> m (Path Rel Dir)
|
=> FilePath -> m (Path Rel)
|
||||||
parseRelDir filepath =
|
parseRelDir filepath =
|
||||||
if not (FilePath.isAbsolute filepath) &&
|
if not (FilePath.isAbsolute filepath) &&
|
||||||
not (null filepath) &&
|
not (null filepath) &&
|
||||||
@ -117,7 +106,7 @@ parseRelDir filepath =
|
|||||||
not (null (normalizeDir filepath)) &&
|
not (null (normalizeDir filepath)) &&
|
||||||
filepath /= "." && filepath /= ".." &&
|
filepath /= "." && filepath /= ".." &&
|
||||||
FilePath.isValid filepath
|
FilePath.isValid filepath
|
||||||
then return (Path (normalizeDir filepath))
|
then return (DPath (normalizeDir filepath))
|
||||||
else throwM (InvalidRelDir filepath)
|
else throwM (InvalidRelDir filepath)
|
||||||
|
|
||||||
-- | Get a location for an absolute file.
|
-- | Get a location for an absolute file.
|
||||||
@ -125,7 +114,7 @@ parseRelDir filepath =
|
|||||||
-- Throws: 'PathParseException'
|
-- Throws: 'PathParseException'
|
||||||
--
|
--
|
||||||
parseAbsFile :: MonadThrow m
|
parseAbsFile :: MonadThrow m
|
||||||
=> FilePath -> m (Path Abs File)
|
=> FilePath -> m (Path Abs)
|
||||||
parseAbsFile filepath =
|
parseAbsFile filepath =
|
||||||
if FilePath.isAbsolute filepath &&
|
if FilePath.isAbsolute filepath &&
|
||||||
not (FilePath.hasTrailingPathSeparator filepath) &&
|
not (FilePath.hasTrailingPathSeparator filepath) &&
|
||||||
@ -133,7 +122,7 @@ parseAbsFile filepath =
|
|||||||
not (hasParentDir filepath) &&
|
not (hasParentDir filepath) &&
|
||||||
not (null (normalizeFile filepath)) &&
|
not (null (normalizeFile filepath)) &&
|
||||||
FilePath.isValid filepath
|
FilePath.isValid filepath
|
||||||
then return (Path (normalizeFile filepath))
|
then return (FPath (normalizeFile filepath))
|
||||||
else throwM (InvalidAbsFile filepath)
|
else throwM (InvalidAbsFile filepath)
|
||||||
|
|
||||||
-- | Get a location for a relative file.
|
-- | Get a location for a relative file.
|
||||||
@ -143,7 +132,7 @@ parseAbsFile filepath =
|
|||||||
-- Throws: 'PathParseException'
|
-- Throws: 'PathParseException'
|
||||||
--
|
--
|
||||||
parseRelFile :: MonadThrow m
|
parseRelFile :: MonadThrow m
|
||||||
=> FilePath -> m (Path Rel File)
|
=> FilePath -> m (Path Rel)
|
||||||
parseRelFile filepath =
|
parseRelFile filepath =
|
||||||
if not (FilePath.isAbsolute filepath ||
|
if not (FilePath.isAbsolute filepath ||
|
||||||
FilePath.hasTrailingPathSeparator filepath) &&
|
FilePath.hasTrailingPathSeparator filepath) &&
|
||||||
@ -153,7 +142,7 @@ parseRelFile filepath =
|
|||||||
not (null (normalizeFile filepath)) &&
|
not (null (normalizeFile filepath)) &&
|
||||||
filepath /= "." && filepath /= ".." &&
|
filepath /= "." && filepath /= ".." &&
|
||||||
FilePath.isValid filepath
|
FilePath.isValid filepath
|
||||||
then return (Path (normalizeFile filepath))
|
then return (FPath (normalizeFile filepath))
|
||||||
else throwM (InvalidRelFile filepath)
|
else throwM (InvalidRelFile filepath)
|
||||||
|
|
||||||
-- | Helper function: check if the filepath has any parent directories in it.
|
-- | Helper function: check if the filepath has any parent directories in it.
|
||||||
@ -181,16 +170,18 @@ mkAbsDir :: FilePath -> Q Exp
|
|||||||
mkAbsDir s =
|
mkAbsDir s =
|
||||||
case parseAbsDir s of
|
case parseAbsDir s of
|
||||||
Left err -> error (show err)
|
Left err -> error (show err)
|
||||||
Right (Path str) ->
|
Right (DPath str) ->
|
||||||
[|Path $(return (LitE (StringL str))) :: Path Abs Dir|]
|
[|DPath $(return (LitE (StringL str))) :: Path Abs|]
|
||||||
|
_ -> error "Invalid Type"
|
||||||
|
|
||||||
-- | Make a 'Path Rel Dir'.
|
-- | Make a 'Path Rel Dir'.
|
||||||
mkRelDir :: FilePath -> Q Exp
|
mkRelDir :: FilePath -> Q Exp
|
||||||
mkRelDir s =
|
mkRelDir s =
|
||||||
case parseRelDir s of
|
case parseRelDir s of
|
||||||
Left err -> error (show err)
|
Left err -> error (show err)
|
||||||
Right (Path str) ->
|
Right (DPath str) ->
|
||||||
[|Path $(return (LitE (StringL str))) :: Path Rel Dir|]
|
[|DPath $(return (LitE (StringL str))) :: Path Rel|]
|
||||||
|
_ -> error "Invalid Type"
|
||||||
|
|
||||||
-- | Make a 'Path Abs File'.
|
-- | Make a 'Path Abs File'.
|
||||||
--
|
--
|
||||||
@ -201,16 +192,18 @@ mkAbsFile :: FilePath -> Q Exp
|
|||||||
mkAbsFile s =
|
mkAbsFile s =
|
||||||
case parseAbsFile s of
|
case parseAbsFile s of
|
||||||
Left err -> error (show err)
|
Left err -> error (show err)
|
||||||
Right (Path str) ->
|
Right (FPath str) ->
|
||||||
[|Path $(return (LitE (StringL str))) :: Path Abs File|]
|
[|FPath $(return (LitE (StringL str))) :: Path Abs|]
|
||||||
|
_ -> error "Invalid Type"
|
||||||
|
|
||||||
-- | Make a 'Path Rel File'.
|
-- | Make a 'Path Rel File'.
|
||||||
mkRelFile :: FilePath -> Q Exp
|
mkRelFile :: FilePath -> Q Exp
|
||||||
mkRelFile s =
|
mkRelFile s =
|
||||||
case parseRelFile s of
|
case parseRelFile s of
|
||||||
Left err -> error (show err)
|
Left err -> error (show err)
|
||||||
Right (Path str) ->
|
Right (FPath str) ->
|
||||||
[|Path $(return (LitE (StringL str))) :: Path Rel File|]
|
[|FPath $(return (LitE (StringL str))) :: Path Rel|]
|
||||||
|
_ -> error "Invalid Type"
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- Conversion
|
-- Conversion
|
||||||
@ -220,24 +213,10 @@ mkRelFile s =
|
|||||||
-- All directories have a trailing slash, so if you want no trailing
|
-- All directories have a trailing slash, so if you want no trailing
|
||||||
-- slash, you can use 'System.FilePath.dropTrailingPathSeparator' from
|
-- slash, you can use 'System.FilePath.dropTrailingPathSeparator' from
|
||||||
-- the filepath package.
|
-- the filepath package.
|
||||||
toFilePath :: Path b t -> FilePath
|
toFilePath :: Path b -> FilePath
|
||||||
toFilePath (Path l) = l
|
toFilePath (FPath l) = l
|
||||||
|
toFilePath (DPath 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
|
||||||
@ -264,8 +243,10 @@ fromRelFile = toFilePath
|
|||||||
--
|
--
|
||||||
-- @x \<\/> $(mkAbsDir …)@
|
-- @x \<\/> $(mkAbsDir …)@
|
||||||
--
|
--
|
||||||
(</>) :: Path b Dir -> Path Rel t -> Path b t
|
(</>) :: MonadThrow m => Path b -> Path Rel -> m (Path b)
|
||||||
(</>) (Path a) (Path b) = Path (a ++ b)
|
(</>) (DPath a) (FPath b) = return $ FPath (a ++ b)
|
||||||
|
(</>) (DPath a) (DPath b) = return $ DPath (a ++ b)
|
||||||
|
(</>) _ _ = throwM InvalidTypeCombination
|
||||||
|
|
||||||
-- | Strip directory from path, making it relative to that directory.
|
-- | Strip directory from path, making it relative to that directory.
|
||||||
-- Throws 'Couldn'tStripPrefixDir' if directory is not a parent of the path.
|
-- Throws 'Couldn'tStripPrefixDir' if directory is not a parent of the path.
|
||||||
@ -283,18 +264,27 @@ fromRelFile = toFilePath
|
|||||||
-- In other words the bases must match.
|
-- In other words the bases must match.
|
||||||
--
|
--
|
||||||
stripDir :: MonadThrow m
|
stripDir :: MonadThrow m
|
||||||
=> Path b Dir -> Path b t -> m (Path Rel t)
|
=> Path b -> Path b -> m (Path Rel)
|
||||||
stripDir (Path p) (Path l) =
|
stripDir (DPath p) (FPath l) =
|
||||||
case stripPrefix p l of
|
case stripPrefix p l of
|
||||||
Nothing -> throwM (Couldn'tStripPrefixDir p l)
|
Nothing -> throwM (Couldn'tStripPrefixDir p l)
|
||||||
Just "" -> throwM (Couldn'tStripPrefixDir p l)
|
Just "" -> throwM (Couldn'tStripPrefixDir p l)
|
||||||
Just ok -> return (Path ok)
|
Just ok -> return (FPath ok)
|
||||||
|
stripDir (DPath p) (DPath l) =
|
||||||
|
case stripPrefix p l of
|
||||||
|
Nothing -> throwM (Couldn'tStripPrefixDir p l)
|
||||||
|
Just "" -> throwM (Couldn'tStripPrefixDir p l)
|
||||||
|
Just ok -> return (DPath ok)
|
||||||
|
stripDir _ _ = throwM InvalidTypeCombination
|
||||||
|
|
||||||
|
|
||||||
-- | 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.
|
||||||
isParentOf :: Path b Dir -> Path b t -> Bool
|
-- Returns False if the first argument is not a directory path.
|
||||||
isParentOf p l =
|
isParentOf :: Path b -> Path b -> Bool
|
||||||
isJust (stripDir p l)
|
isParentOf p@(DPath _) l@(DPath _) = isJust (stripDir p l)
|
||||||
|
isParentOf p@(DPath _) l@(FPath _) = isJust (stripDir p l)
|
||||||
|
isParentOf _ _ = False
|
||||||
|
|
||||||
-- | Take the absolute parent directory from the absolute path.
|
-- | Take the absolute parent directory from the absolute path.
|
||||||
--
|
--
|
||||||
@ -306,29 +296,24 @@ isParentOf p l =
|
|||||||
--
|
--
|
||||||
-- @parent (parent \"\/\") = \"\/\"@
|
-- @parent (parent \"\/\") = \"\/\"@
|
||||||
--
|
--
|
||||||
parent :: Path Abs t -> Path Abs Dir
|
parent :: Path Abs -> Path Abs
|
||||||
parent (Path fp) =
|
parent (DPath fp) =
|
||||||
Path (normalizeDir (FilePath.takeDirectory (FilePath.dropTrailingPathSeparator fp)))
|
DPath (normalizeDir (FilePath.takeDirectory (FilePath.dropTrailingPathSeparator fp)))
|
||||||
|
parent (FPath fp) =
|
||||||
|
DPath (normalizeDir (FilePath.takeDirectory (FilePath.dropTrailingPathSeparator fp)))
|
||||||
|
|
||||||
-- | Extract the file part of a path.
|
-- | Extract the file/directory part of a path.
|
||||||
--
|
--
|
||||||
-- The following properties hold:
|
-- The following properties hold:
|
||||||
--
|
--
|
||||||
-- @filename (p \<\/> a) == filename a@
|
-- @filename (p \<\/> a) == filename a@
|
||||||
--
|
--
|
||||||
filename :: Path b File -> Path Rel File
|
filename :: Path b -> Path Rel
|
||||||
filename (Path l) =
|
filename (FPath l) =
|
||||||
Path (normalizeFile (FilePath.takeFileName l))
|
FPath (normalizeFile (FilePath.takeFileName l))
|
||||||
|
filename (DPath l) =
|
||||||
|
DPath (last (FilePath.splitPath l))
|
||||||
|
|
||||||
-- | Extract the last directory name of a path.
|
|
||||||
--
|
|
||||||
-- The following properties hold:
|
|
||||||
--
|
|
||||||
-- @dirname (p \<\/> a) == dirname a@
|
|
||||||
--
|
|
||||||
dirname :: Path b Dir -> Path Rel Dir
|
|
||||||
dirname (Path l) =
|
|
||||||
Path (last (FilePath.splitPath l))
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- Internal functions
|
-- Internal functions
|
||||||
@ -348,3 +333,4 @@ normalizeFile =
|
|||||||
where clean "./" = ""
|
where clean "./" = ""
|
||||||
clean ('/':'/':xs) = clean ('/':xs)
|
clean ('/':'/':xs) = clean ('/':xs)
|
||||||
clean x = x
|
clean x = x
|
||||||
|
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
{-# LANGUAGE DeriveDataTypeable #-}
|
{-# LANGUAGE DeriveDataTypeable #-}
|
||||||
|
|
||||||
|
-- TODO: - remove undefined in Ord instance
|
||||||
|
-- - use viewpatterns/patternsynonyms so we don't need to
|
||||||
|
-- export the constructors
|
||||||
|
|
||||||
-- | Internal types and functions.
|
-- | Internal types and functions.
|
||||||
|
|
||||||
module Path.Internal
|
module Path.Internal
|
||||||
@ -18,7 +22,8 @@ import Data.Data
|
|||||||
--
|
--
|
||||||
-- 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
|
data Path b = FPath FilePath
|
||||||
|
| DPath FilePath
|
||||||
deriving (Typeable)
|
deriving (Typeable)
|
||||||
|
|
||||||
-- | String equality.
|
-- | String equality.
|
||||||
@ -26,24 +31,31 @@ newtype Path b t = Path FilePath
|
|||||||
-- The following property holds:
|
-- The following property holds:
|
||||||
--
|
--
|
||||||
-- @show x == show y ≡ x == y@
|
-- @show x == show y ≡ x == y@
|
||||||
instance Eq (Path b t) where
|
instance Eq (Path b) where
|
||||||
(==) (Path x) (Path y) = x == y
|
(==) (FPath x) (FPath y) = x == y
|
||||||
|
(==) (DPath x) (DPath y) = x == y
|
||||||
|
(==) _ _ = False
|
||||||
|
|
||||||
-- | String ordering.
|
-- | String ordering.
|
||||||
--
|
--
|
||||||
-- The following property holds:
|
-- The following property holds:
|
||||||
--
|
--
|
||||||
-- @show x \`compare\` show y ≡ x \`compare\` y@
|
-- @show x \`compare\` show y ≡ x \`compare\` y@
|
||||||
instance Ord (Path b t) where
|
instance Ord (Path b) where
|
||||||
compare (Path x) (Path y) = compare x y
|
compare (FPath x) (FPath y) = compare x y
|
||||||
|
compare (DPath x) (DPath y) = compare x y
|
||||||
|
compare _ _ = undefined
|
||||||
|
|
||||||
-- | Same as 'Path.toFilePath'.
|
-- | Same as 'Path.toFilePath'.
|
||||||
--
|
--
|
||||||
-- The following property holds:
|
-- The following property holds:
|
||||||
--
|
--
|
||||||
-- @x == y ≡ show x == show y@
|
-- @x == y ≡ show x == show y@
|
||||||
instance Show (Path b t) where
|
instance Show (Path b) where
|
||||||
show (Path x) = show x
|
show (FPath x) = show x
|
||||||
|
show (DPath x) = show x
|
||||||
|
|
||||||
|
instance NFData (Path b) where
|
||||||
|
rnf (FPath x) = rnf x
|
||||||
|
rnf (DPath x) = rnf x
|
||||||
|
|
||||||
instance NFData (Path b t) where
|
|
||||||
rnf (Path x) = rnf x
|
|
||||||
|
Loading…
Reference in New Issue
Block a user