{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ViewPatterns #-}
module Distribution.Solver.Types.ProjectConfigPath
(
ProjectConfigPath(..)
, projectConfigPathRoot
, nullProjectConfigPath
, consProjectConfigPath
, unconsProjectConfigPath
, docProjectConfigPath
, docProjectConfigFiles
, cyclicalImportMsg
, untrimmedUriImportMsg
, docProjectConfigPathFailReason
, quoteUntrimmed
, isCyclicConfigPath
, isTopLevelConfigPath
, isUntrimmedUriConfigPath
, canonicalizeConfigPath
) where
import Distribution.Solver.Compat.Prelude hiding (toList, (<>))
import qualified Distribution.Solver.Compat.Prelude as P ((<>))
import Prelude (sequence)
import Data.Coerce (coerce)
import Data.List.NonEmpty ((<|))
import Network.URI (parseURI, parseAbsoluteURI)
import System.Directory
import System.FilePath hiding (splitPath)
import qualified System.FilePath as FP (splitPath)
import qualified System.FilePath.Posix as Posix
import qualified System.FilePath.Windows as Windows
import qualified Data.List.NonEmpty as NE
import Distribution.Solver.Modular.Version (VR)
import Distribution.Pretty (prettyShow, Pretty(..))
import Distribution.Utils.String (trim)
import Text.PrettyPrint
import Distribution.Simple.Utils (ordNub)
import Distribution.System (OS(Windows), buildOS)
newtype ProjectConfigPath = ProjectConfigPath (NonEmpty FilePath)
deriving (ProjectConfigPath -> ProjectConfigPath -> Bool
(ProjectConfigPath -> ProjectConfigPath -> Bool)
-> (ProjectConfigPath -> ProjectConfigPath -> Bool)
-> Eq ProjectConfigPath
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ProjectConfigPath -> ProjectConfigPath -> Bool
== :: ProjectConfigPath -> ProjectConfigPath -> Bool
$c/= :: ProjectConfigPath -> ProjectConfigPath -> Bool
/= :: ProjectConfigPath -> ProjectConfigPath -> Bool
Eq, Int -> ProjectConfigPath -> ShowS
[ProjectConfigPath] -> ShowS
ProjectConfigPath -> FilePath
(Int -> ProjectConfigPath -> ShowS)
-> (ProjectConfigPath -> FilePath)
-> ([ProjectConfigPath] -> ShowS)
-> Show ProjectConfigPath
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ProjectConfigPath -> ShowS
showsPrec :: Int -> ProjectConfigPath -> ShowS
$cshow :: ProjectConfigPath -> FilePath
show :: ProjectConfigPath -> FilePath
$cshowList :: [ProjectConfigPath] -> ShowS
showList :: [ProjectConfigPath] -> ShowS
Show, (forall x. ProjectConfigPath -> Rep ProjectConfigPath x)
-> (forall x. Rep ProjectConfigPath x -> ProjectConfigPath)
-> Generic ProjectConfigPath
forall x. Rep ProjectConfigPath x -> ProjectConfigPath
forall x. ProjectConfigPath -> Rep ProjectConfigPath x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ProjectConfigPath -> Rep ProjectConfigPath x
from :: forall x. ProjectConfigPath -> Rep ProjectConfigPath x
$cto :: forall x. Rep ProjectConfigPath x -> ProjectConfigPath
to :: forall x. Rep ProjectConfigPath x -> ProjectConfigPath
Generic)
instance Pretty ProjectConfigPath where
pretty :: ProjectConfigPath -> Doc
pretty = ProjectConfigPath -> Doc
docProjectConfigPath
instance Ord ProjectConfigPath where
compare :: ProjectConfigPath -> ProjectConfigPath -> Ordering
compare pa :: ProjectConfigPath
pa@(ProjectConfigPath (NonEmpty FilePath -> [FilePath]
forall a. NonEmpty a -> [a]
NE.toList -> [FilePath]
as)) pb :: ProjectConfigPath
pb@(ProjectConfigPath (NonEmpty FilePath -> [FilePath]
forall a. NonEmpty a -> [a]
NE.toList -> [FilePath]
bs)) =
case ([FilePath]
as, [FilePath]
bs) of
([FilePath
a], [FilePath
b]) -> [FilePath] -> [FilePath] -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (FilePath -> [FilePath]
splitPath FilePath
a) (FilePath -> [FilePath]
splitPath FilePath
b)
([FilePath
_], [FilePath]
_) -> Ordering
LT
([FilePath]
_, [FilePath
_]) -> Ordering
GT
(FilePath
a:[FilePath]
_, FilePath
b:[FilePath]
_) -> case (FilePath -> Maybe URI
parseAbsoluteURI FilePath
a, FilePath -> Maybe URI
parseAbsoluteURI FilePath
b) of
(Just URI
ua, Just URI
ub) -> URI -> URI -> Ordering
forall a. Ord a => a -> a -> Ordering
compare URI
ua URI
ub Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
P.<> Maybe ProjectConfigPath -> Maybe ProjectConfigPath -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Maybe ProjectConfigPath
aImporters Maybe ProjectConfigPath
bImporters
(Just URI
_, Maybe URI
Nothing) -> Ordering
GT
(Maybe URI
Nothing, Just URI
_) -> Ordering
LT
(Maybe URI
Nothing, Maybe URI
Nothing) -> [FilePath] -> [FilePath] -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (FilePath -> [FilePath]
splitPath FilePath
a) (FilePath -> [FilePath]
splitPath FilePath
b) Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
P.<> Maybe ProjectConfigPath -> Maybe ProjectConfigPath -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Maybe ProjectConfigPath
aImporters Maybe ProjectConfigPath
bImporters
([FilePath], [FilePath])
_ ->
Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ([FilePath] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilePath]
as) ([FilePath] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilePath]
bs)
Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
P.<> Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ([[FilePath]] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [[FilePath]]
aPaths) ([[FilePath]] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [[FilePath]]
bPaths)
Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
P.<> [[FilePath]] -> [[FilePath]] -> Ordering
forall a. Ord a => a -> a -> Ordering
compare [[FilePath]]
aPaths [[FilePath]]
bPaths
where
splitPath :: FilePath -> [FilePath]
splitPath = FilePath -> [FilePath]
FP.splitPath (FilePath -> [FilePath]) -> ShowS -> FilePath -> [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
normSep where
normSep :: ShowS
normSep FilePath
p =
if OS
buildOS OS -> OS -> Bool
forall a. Eq a => a -> a -> Bool
== OS
Windows
then
[FilePath] -> FilePath
Windows.joinPath ([FilePath] -> FilePath) -> [FilePath] -> FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> [FilePath]
Windows.splitDirectories
[if Char -> Bool
Posix.isPathSeparator Char
c then Char
Windows.pathSeparator else Char
c| Char
c <- FilePath
p]
else
[FilePath] -> FilePath
Posix.joinPath ([FilePath] -> FilePath) -> [FilePath] -> FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> [FilePath]
Posix.splitDirectories
[if Char -> Bool
Windows.isPathSeparator Char
c then Char
Posix.pathSeparator else Char
c| Char
c <- FilePath
p]
aPaths :: [[FilePath]]
aPaths = FilePath -> [FilePath]
splitPath (FilePath -> [FilePath]) -> [FilePath] -> [[FilePath]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [FilePath]
as
bPaths :: [[FilePath]]
bPaths = FilePath -> [FilePath]
splitPath (FilePath -> [FilePath]) -> [FilePath] -> [[FilePath]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [FilePath]
bs
aImporters :: Maybe ProjectConfigPath
aImporters = (FilePath, Maybe ProjectConfigPath) -> Maybe ProjectConfigPath
forall a b. (a, b) -> b
snd ((FilePath, Maybe ProjectConfigPath) -> Maybe ProjectConfigPath)
-> (FilePath, Maybe ProjectConfigPath) -> Maybe ProjectConfigPath
forall a b. (a -> b) -> a -> b
$ ProjectConfigPath -> (FilePath, Maybe ProjectConfigPath)
unconsProjectConfigPath ProjectConfigPath
pa
bImporters :: Maybe ProjectConfigPath
bImporters = (FilePath, Maybe ProjectConfigPath) -> Maybe ProjectConfigPath
forall a b. (a, b) -> b
snd ((FilePath, Maybe ProjectConfigPath) -> Maybe ProjectConfigPath)
-> (FilePath, Maybe ProjectConfigPath) -> Maybe ProjectConfigPath
forall a b. (a -> b) -> a -> b
$ ProjectConfigPath -> (FilePath, Maybe ProjectConfigPath)
unconsProjectConfigPath ProjectConfigPath
pb
instance Binary ProjectConfigPath
instance Structured ProjectConfigPath
docProjectConfigPath :: ProjectConfigPath -> Doc
docProjectConfigPath :: ProjectConfigPath -> Doc
docProjectConfigPath (ProjectConfigPath (FilePath
p :| [])) = FilePath -> Doc
quoteUntrimmed FilePath
p
docProjectConfigPath (ProjectConfigPath (FilePath
p :| [FilePath]
ps)) = [Doc] -> Doc
vcat ([Doc] -> Doc) -> [Doc] -> Doc
forall a b. (a -> b) -> a -> b
$ FilePath -> Doc
quoteUntrimmed FilePath
p Doc -> [Doc] -> [Doc]
forall a. a -> [a] -> [a]
:
[ FilePath -> Doc
text FilePath
" " Doc -> Doc -> Doc
<+> FilePath -> Doc
text FilePath
"imported by:" Doc -> Doc -> Doc
<+> FilePath -> Doc
quoteUntrimmed FilePath
l | FilePath
l <- [FilePath]
ps ]
quoteUntrimmed :: FilePath -> Doc
quoteUntrimmed :: FilePath -> Doc
quoteUntrimmed FilePath
s = if ShowS
trim FilePath
s FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
/= FilePath
s then Doc -> Doc
quotes (FilePath -> Doc
text FilePath
s) else FilePath -> Doc
text FilePath
s
docProjectConfigFiles :: [ProjectConfigPath] -> Doc
docProjectConfigFiles :: [ProjectConfigPath] -> Doc
docProjectConfigFiles [ProjectConfigPath]
ps = [Doc] -> Doc
vcat
[ FilePath -> Doc
text FilePath
"-" Doc -> Doc -> Doc
<+> FilePath -> Doc
text FilePath
p
| FilePath
p <- [FilePath] -> [FilePath]
forall a. Ord a => [a] -> [a]
ordNub [ FilePath
p | ProjectConfigPath (FilePath
p :| [FilePath]
_) <- [ProjectConfigPath]
ps ]
]
cyclicalImportMsg :: ProjectConfigPath -> Doc
cyclicalImportMsg :: ProjectConfigPath -> Doc
cyclicalImportMsg path :: ProjectConfigPath
path@(ProjectConfigPath (FilePath
duplicate :| [FilePath]
_)) =
[Doc] -> Doc
vcat
[ FilePath -> Doc
text FilePath
"cyclical import of" Doc -> Doc -> Doc
<+> FilePath -> Doc
text FilePath
duplicate Doc -> Doc -> Doc
<> Doc
semi
, Int -> Doc -> Doc
nest Int
2 (ProjectConfigPath -> Doc
docProjectConfigPath ProjectConfigPath
path)
]
untrimmedUriImportMsg :: Doc -> ProjectConfigPath -> Doc
untrimmedUriImportMsg :: Doc -> ProjectConfigPath -> Doc
untrimmedUriImportMsg Doc
intro ProjectConfigPath
path =
[Doc] -> Doc
vcat
[ Doc
intro Doc -> Doc -> Doc
<+> FilePath -> Doc
text FilePath
"import has leading or trailing whitespace" Doc -> Doc -> Doc
<> Doc
semi
, Int -> Doc -> Doc
nest Int
2 (ProjectConfigPath -> Doc
docProjectConfigPath ProjectConfigPath
path)
]
docProjectConfigPathFailReason :: VR -> ProjectConfigPath -> Doc
docProjectConfigPathFailReason :: VR -> ProjectConfigPath -> Doc
docProjectConfigPathFailReason VR
vr ProjectConfigPath
pcp
| ProjectConfigPath (FilePath
p :| []) <- ProjectConfigPath
pcp =
FilePath -> Doc
constraint FilePath
p
| ProjectConfigPath (FilePath
p :| [FilePath]
ps) <- ProjectConfigPath
pcp = [Doc] -> Doc
vcat
[ FilePath -> Doc
constraint FilePath
p
, [Doc] -> Doc
cat [Int -> Doc -> Doc
nest Int
2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ FilePath -> Doc
text FilePath
"imported by:" Doc -> Doc -> Doc
<+> FilePath -> Doc
text FilePath
l | FilePath
l <- [FilePath]
ps ]
]
where
pathRequiresVersion :: FilePath -> Doc
pathRequiresVersion FilePath
p = FilePath -> Doc
text FilePath
p Doc -> Doc -> Doc
<+> FilePath -> Doc
text FilePath
"requires" Doc -> Doc -> Doc
<+> FilePath -> Doc
text (VR -> FilePath
forall a. Pretty a => a -> FilePath
prettyShow VR
vr)
constraint :: FilePath -> Doc
constraint FilePath
p = Doc -> Doc
parens (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ FilePath -> Doc
text FilePath
"constraint from" Doc -> Doc -> Doc
<+> FilePath -> Doc
pathRequiresVersion FilePath
p
projectConfigPathRoot :: ProjectConfigPath -> FilePath
projectConfigPathRoot :: ProjectConfigPath -> FilePath
projectConfigPathRoot (ProjectConfigPath NonEmpty FilePath
xs) = NonEmpty FilePath -> FilePath
forall a. NonEmpty a -> a
last NonEmpty FilePath
xs
nullProjectConfigPath :: ProjectConfigPath
nullProjectConfigPath :: ProjectConfigPath
nullProjectConfigPath = NonEmpty FilePath -> ProjectConfigPath
ProjectConfigPath (NonEmpty FilePath -> ProjectConfigPath)
-> NonEmpty FilePath -> ProjectConfigPath
forall a b. (a -> b) -> a -> b
$ FilePath
"unused" FilePath -> [FilePath] -> NonEmpty FilePath
forall a. a -> [a] -> NonEmpty a
:| []
isCyclicConfigPath :: ProjectConfigPath -> Bool
isCyclicConfigPath :: ProjectConfigPath -> Bool
isCyclicConfigPath (ProjectConfigPath NonEmpty FilePath
p) = NonEmpty FilePath -> Int
forall a. NonEmpty a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length NonEmpty FilePath
p Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= NonEmpty FilePath -> Int
forall a. NonEmpty a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (NonEmpty FilePath -> NonEmpty FilePath
forall a. Eq a => NonEmpty a -> NonEmpty a
NE.nub NonEmpty FilePath
p)
isUntrimmedUriConfigPath :: ProjectConfigPath -> Bool
isUntrimmedUriConfigPath :: ProjectConfigPath -> Bool
isUntrimmedUriConfigPath (ProjectConfigPath (FilePath
p :| [FilePath]
_)) = let p' :: FilePath
p' = ShowS
trim FilePath
p in FilePath
p' FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
/= FilePath
p Bool -> Bool -> Bool
&& FilePath -> Bool
isURI FilePath
p'
isTopLevelConfigPath :: ProjectConfigPath -> Bool
isTopLevelConfigPath :: ProjectConfigPath -> Bool
isTopLevelConfigPath (ProjectConfigPath NonEmpty FilePath
p) = NonEmpty FilePath -> Int
forall a. NonEmpty a -> Int
NE.length NonEmpty FilePath
p Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1
consProjectConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath
consProjectConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath
consProjectConfigPath FilePath
p ProjectConfigPath
ps = NonEmpty FilePath -> ProjectConfigPath
ProjectConfigPath (FilePath
p FilePath -> NonEmpty FilePath -> NonEmpty FilePath
forall a. a -> NonEmpty a -> NonEmpty a
<| ProjectConfigPath -> NonEmpty FilePath
forall a b. Coercible a b => a -> b
coerce ProjectConfigPath
ps)
unconsProjectConfigPath :: ProjectConfigPath -> (FilePath, Maybe ProjectConfigPath)
unconsProjectConfigPath :: ProjectConfigPath -> (FilePath, Maybe ProjectConfigPath)
unconsProjectConfigPath ProjectConfigPath
ps = (NonEmpty FilePath -> ProjectConfigPath)
-> Maybe (NonEmpty FilePath) -> Maybe ProjectConfigPath
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap NonEmpty FilePath -> ProjectConfigPath
ProjectConfigPath (Maybe (NonEmpty FilePath) -> Maybe ProjectConfigPath)
-> (FilePath, Maybe (NonEmpty FilePath))
-> (FilePath, Maybe ProjectConfigPath)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty FilePath -> (FilePath, Maybe (NonEmpty FilePath))
forall a. NonEmpty a -> (a, Maybe (NonEmpty a))
NE.uncons (ProjectConfigPath -> NonEmpty FilePath
forall a b. Coercible a b => a -> b
coerce ProjectConfigPath
ps)
makeRelativeConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath
makeRelativeConfigPath :: FilePath -> ProjectConfigPath -> ProjectConfigPath
makeRelativeConfigPath FilePath
dir (ProjectConfigPath NonEmpty FilePath
p) =
NonEmpty FilePath -> ProjectConfigPath
ProjectConfigPath
(NonEmpty FilePath -> ProjectConfigPath)
-> NonEmpty FilePath -> ProjectConfigPath
forall a b. (a -> b) -> a -> b
$ (\segment :: FilePath
segment@(ShowS
trim -> FilePath
trimSegment) -> (if FilePath -> Bool
isURI FilePath
trimSegment then FilePath
trimSegment else FilePath -> ShowS
makeRelative FilePath
dir FilePath
segment))
ShowS -> NonEmpty FilePath -> NonEmpty FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty FilePath
p
canonicalizeConfigPath :: FilePath -> ProjectConfigPath -> IO ProjectConfigPath
canonicalizeConfigPath :: FilePath -> ProjectConfigPath -> IO ProjectConfigPath
canonicalizeConfigPath FilePath
d (ProjectConfigPath NonEmpty FilePath
p) = do
NonEmpty FilePath
xs <- NonEmpty (IO FilePath) -> IO (NonEmpty FilePath)
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => NonEmpty (m a) -> m (NonEmpty a)
sequence (NonEmpty (IO FilePath) -> IO (NonEmpty FilePath))
-> NonEmpty (IO FilePath) -> IO (NonEmpty FilePath)
forall a b. (a -> b) -> a -> b
$ (FilePath -> IO FilePath -> IO FilePath)
-> IO FilePath -> NonEmpty FilePath -> NonEmpty (IO FilePath)
forall (f :: * -> *) a b.
Foldable f =>
(a -> b -> b) -> b -> f a -> NonEmpty b
NE.scanr (\importee :: FilePath
importee@(ShowS
trim -> FilePath
trimImportee) -> (IO FilePath -> (FilePath -> IO FilePath) -> IO FilePath
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \importer :: FilePath
importer@(ShowS
trim -> FilePath
trimImporter) ->
if FilePath -> Bool
isURI FilePath
trimImportee Bool -> Bool -> Bool
|| FilePath -> Bool
isURI FilePath
trimImporter
then FilePath -> IO FilePath
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FilePath
trimImportee
else FilePath -> IO FilePath
canonicalizePath (FilePath -> IO FilePath) -> FilePath -> IO FilePath
forall a b. (a -> b) -> a -> b
$ FilePath
d FilePath -> ShowS
</> ShowS
takeDirectory FilePath
importer FilePath -> ShowS
</> FilePath
importee))
(FilePath -> IO FilePath
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FilePath
".") NonEmpty FilePath
p
ProjectConfigPath -> IO ProjectConfigPath
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ProjectConfigPath -> IO ProjectConfigPath)
-> ([FilePath] -> ProjectConfigPath)
-> [FilePath]
-> IO ProjectConfigPath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ProjectConfigPath -> ProjectConfigPath
makeRelativeConfigPath FilePath
d (ProjectConfigPath -> ProjectConfigPath)
-> ([FilePath] -> ProjectConfigPath)
-> [FilePath]
-> ProjectConfigPath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty FilePath -> ProjectConfigPath
ProjectConfigPath (NonEmpty FilePath -> ProjectConfigPath)
-> ([FilePath] -> NonEmpty FilePath)
-> [FilePath]
-> ProjectConfigPath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [FilePath] -> NonEmpty FilePath
forall a. HasCallStack => [a] -> NonEmpty a
NE.fromList ([FilePath] -> IO ProjectConfigPath)
-> [FilePath] -> IO ProjectConfigPath
forall a b. (a -> b) -> a -> b
$ NonEmpty FilePath -> [FilePath]
forall a. NonEmpty a -> [a]
NE.init NonEmpty FilePath
xs
isURI :: FilePath -> Bool
isURI :: FilePath -> Bool
isURI = Maybe URI -> Bool
forall a. Maybe a -> Bool
isJust (Maybe URI -> Bool) -> (FilePath -> Maybe URI) -> FilePath -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Maybe URI
parseURI