1 {-# LANGUAGE CPP, DeriveGeneric, DeriveFunctor,
2 RecordWildCards, NamedFieldPuns #-}
3 {-# LANGUAGE ScopedTypeVariables #-}
6 {-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
7 -----------------------------------------------------------------------------
9 -- Module : Distribution.Client.TargetSelector
10 -- Copyright : (c) Duncan Coutts 2012, 2015, 2016
13 -- Maintainer : duncan@community.haskell.org
15 -- Handling for user-specified target selectors.
17 -----------------------------------------------------------------------------
18 module Distribution
.Client
.TargetSelector
(
22 TargetImplicitCwd
(..),
25 SubComponentTarget
(..),
29 -- * Reading target selectors
31 TargetSelectorProblem
(..),
32 reportTargetSelectorProblems
,
38 readTargetSelectorsWith
,
44 import Distribution
.Client
.Compat
.Prelude
46 import Distribution
.Package
47 ( Package
(..), PackageId
, PackageName
, packageName
)
48 import Distribution
.Types
.UnqualComponentName
49 ( UnqualComponentName
, mkUnqualComponentName
, unUnqualComponentName
50 , packageNameToUnqualComponentName
)
51 import Distribution
.Client
.Types
52 ( PackageLocation
(..), PackageSpecifier
(..) )
54 import Distribution
.PackageDescription
57 , TestSuite
(..), TestSuiteInterface
(..), testModules
58 , Benchmark
(..), BenchmarkInterface
(..), benchmarkModules
59 , BuildInfo
(..), explicitLibModules
, exeModules
)
60 import Distribution
.PackageDescription
.Configuration
61 ( flattenPackageDescription
)
62 import Distribution
.Solver
.Types
.SourcePackage
64 import Distribution
.ModuleName
65 ( ModuleName
, toFilePath
)
66 import Distribution
.Simple
.LocalBuildInfo
67 ( Component
(..), ComponentName
(..), LibraryName
(..)
68 , pkgComponents
, componentName
, componentBuildInfo
)
69 import Distribution
.Types
.ForeignLib
71 import Distribution
.Simple
.Utils
72 ( die
', lowercase
, ordNub
)
73 import Distribution
.Client
.Utils
74 ( makeRelativeCanonical
)
77 ( stripPrefix
, groupBy )
78 import qualified Data
.List
.NonEmpty
as NE
79 import qualified Data
.Map
.Lazy
as Map
.Lazy
80 import qualified Data
.Map
.Strict
as Map
81 import qualified Data
.Set
as Set
82 import Control
.Arrow
((&&&))
85 import qualified Distribution
.Deprecated
.ReadP
as Parse
86 import Distribution
.Deprecated
.ReadP
88 import Distribution
.Deprecated
.ParseUtils
90 import System
.FilePath as FilePath
91 ( takeExtension
, dropExtension
92 , splitDirectories
, joinPath
, splitPath
)
93 import qualified System
.Directory
as IO
94 ( doesFileExist, doesDirectoryExist, canonicalizePath
95 , getCurrentDirectory )
96 import System
.FilePath
97 ( (</>), (<.>), normalise
, dropTrailingPathSeparator
, equalFilePath
)
98 import Text
.EditDistance
99 ( defaultEditCosts
, restrictedDamerauLevenshteinDistance
)
100 import Distribution
.Utils
.Path
102 import qualified Prelude
(foldr1)
104 -- ------------------------------------------------------------
105 -- * Target selector terms
106 -- ------------------------------------------------------------
108 -- | A target selector is expression selecting a set of components (as targets
109 -- for a actions like @build@, @run@, @test@ etc). A target selector
110 -- corresponds to the user syntax for referring to targets on the command line.
112 -- From the users point of view a target can be many things: packages, dirs,
113 -- component names, files etc. Internally we consider a target to be a specific
114 -- component (or module\/file within a component), and all the users' notions
115 -- of targets are just different ways of referring to these component targets.
117 -- So target selectors are expressions in the sense that they are interpreted
118 -- to refer to one or more components. For example a 'TargetPackage' gets
119 -- interpreted differently by different commands to refer to all or a subset
120 -- of components within the package.
122 -- The syntax has lots of optional parts:
124 -- > [ package name | package dir | package .cabal file ]
125 -- > [ [lib:|exe:] component name ]
126 -- > [ module name | source file ]
128 data TargetSelector
=
130 -- | One (or more) packages as a whole, or all the components of a
131 -- particular kind within the package(s).
133 -- These are always packages that are local to the project. In the case
134 -- that there is more than one, they all share the same directory location.
136 TargetPackage TargetImplicitCwd
[PackageId
] (Maybe ComponentKindFilter
)
138 -- | A package specified by name. This may refer to @extra-packages@ from
139 -- the @cabal.project@ file, or a dependency of a known project package or
140 -- could refer to a package from a hackage archive. It needs further
141 -- context to resolve to a specific package.
143 | TargetPackageNamed PackageName
(Maybe ComponentKindFilter
)
145 -- | All packages, or all components of a particular kind in all packages.
147 | TargetAllPackages
(Maybe ComponentKindFilter
)
149 -- | A specific component in a package within the project.
151 | TargetComponent PackageId ComponentName SubComponentTarget
153 -- | A component in a package, but where it cannot be verified that the
154 -- package has such a component, or because the package is itself not
157 | TargetComponentUnknown PackageName
158 (Either UnqualComponentName ComponentName
)
160 deriving (Eq
, Ord
, Show, Generic
)
162 -- | Does this 'TargetPackage' selector arise from syntax referring to a
163 -- package in the current directory (e.g. @tests@ or no giving no explicit
164 -- target at all) or does it come from syntax referring to a package name
167 data TargetImplicitCwd
= TargetImplicitCwd | TargetExplicitNamed
168 deriving (Eq
, Ord
, Show, Generic
)
170 data ComponentKind
= LibKind | FLibKind | ExeKind | TestKind | BenchKind
171 deriving (Eq
, Ord
, Enum
, Show)
173 type ComponentKindFilter
= ComponentKind
175 -- | Either the component as a whole or detail about a file or module target
176 -- within a component.
178 data SubComponentTarget
=
180 -- | The component as a whole
183 -- | A specific module within a component.
184 | ModuleTarget ModuleName
186 -- | A specific file within a component. Note that this does not carry the
188 | FileTarget
FilePath
189 deriving (Eq
, Ord
, Show, Generic
)
191 instance Binary SubComponentTarget
192 instance Structured SubComponentTarget
195 -- ------------------------------------------------------------
196 -- * Top level, do everything
197 -- ------------------------------------------------------------
200 -- | Parse a bunch of command line args as 'TargetSelector's, failing with an
201 -- error if any are unrecognised. The possible target selectors are based on
202 -- the available packages (and their locations).
204 readTargetSelectors
:: [PackageSpecifier
(SourcePackage
(PackageLocation a
))]
205 -> Maybe ComponentKindFilter
206 -- ^ This parameter is used when there are ambiguous selectors.
207 -- If it is 'Just', then we attempt to resolve ambiguity
208 -- by applying it, since otherwise there is no way to allow
209 -- contextually valid yet syntactically ambiguous selectors.
212 -> IO (Either [TargetSelectorProblem
] [TargetSelector
])
213 readTargetSelectors
= readTargetSelectorsWith defaultDirActions
215 readTargetSelectorsWith
:: (Applicative m
, Monad m
) => DirActions m
216 -> [PackageSpecifier
(SourcePackage
(PackageLocation a
))]
217 -> Maybe ComponentKindFilter
219 -> m
(Either [TargetSelectorProblem
] [TargetSelector
])
220 readTargetSelectorsWith dirActions
@DirActions
{} pkgs mfilter targetStrs
=
221 case parseTargetStrings targetStrs
of
222 ([], usertargets
) -> do
223 usertargets
' <- traverse
(getTargetStringFileStatus dirActions
) usertargets
224 knowntargets
<- getKnownTargets dirActions pkgs
225 case resolveTargetSelectors knowntargets usertargets
' mfilter
of
226 ([], btargets
) -> return (Right btargets
)
227 (problems
, _
) -> return (Left problems
)
228 (strs
, _
) -> return (Left
(map TargetSelectorUnrecognised strs
))
231 data DirActions m
= DirActions
{
232 doesFileExist :: FilePath -> m
Bool,
233 doesDirectoryExist :: FilePath -> m
Bool,
234 canonicalizePath
:: FilePath -> m
FilePath,
235 getCurrentDirectory :: m
FilePath
238 defaultDirActions
:: DirActions
IO
241 doesFileExist = IO.doesFileExist,
242 doesDirectoryExist = IO.doesDirectoryExist,
243 -- Workaround for <https://github.com/haskell/directory/issues/63>
244 canonicalizePath
= IO.canonicalizePath
. dropTrailingPathSeparator
,
245 getCurrentDirectory = IO.getCurrentDirectory
248 makeRelativeToCwd
:: Applicative m
=> DirActions m
-> FilePath -> m
FilePath
249 makeRelativeToCwd DirActions
{..} path
=
250 makeRelativeCanonical
<$> canonicalizePath path
<*> getCurrentDirectory
253 -- ------------------------------------------------------------
254 -- * Parsing target strings
255 -- ------------------------------------------------------------
257 -- | The outline parse of a target selector. It takes one of the forms:
262 -- > str1:str2:str3:str4
266 | TargetString2
String String
267 | TargetString3
String String String
268 | TargetString4
String String String String
269 | TargetString5
String String String String String
270 | TargetString7
String String String String String String String
273 -- | Parse a bunch of 'TargetString's (purely without throwing exceptions).
275 parseTargetStrings
:: [String] -> ([String], [TargetString
])
278 . map (\str
-> maybe (Left str
) Right
(parseTargetString str
))
280 parseTargetString
:: String -> Maybe TargetString
282 readPToMaybe parseTargetApprox
284 parseTargetApprox
:: Parse
.ReadP r TargetString
287 return (TargetString1 a
))
291 return (TargetString2 a b
))
297 return (TargetString3 a b c
))
305 return (TargetString4 a b c d
))
315 return (TargetString5 a b c d e
))
329 return (TargetString7 a b c d e f g
))
331 token
= Parse
.munch1
(\x
-> not (isSpace x
) && x
/= ':')
332 tokenQ
= parseHaskellString
<++ token
333 token0
= Parse
.munch
(\x
-> not (isSpace x
) && x
/= ':')
334 tokenQ0
= parseHaskellString
<++ token0
335 parseHaskellString
:: Parse
.ReadP r
String
336 parseHaskellString
= Parse
.readS_to_P
reads
339 -- | Render a 'TargetString' back as the external syntax. This is mainly for
342 showTargetString
:: TargetString
-> String
343 showTargetString
= intercalate
":" . components
345 components
(TargetString1 s1
) = [s1
]
346 components
(TargetString2 s1 s2
) = [s1
,s2
]
347 components
(TargetString3 s1 s2 s3
) = [s1
,s2
,s3
]
348 components
(TargetString4 s1 s2 s3 s4
) = [s1
,s2
,s3
,s4
]
349 components
(TargetString5 s1 s2 s3 s4 s5
) = [s1
,s2
,s3
,s4
,s5
]
350 components
(TargetString7 s1 s2 s3 s4 s5 s6 s7
) = [s1
,s2
,s3
,s4
,s5
,s6
,s7
]
352 showTargetSelector
:: TargetSelector
-> String
353 showTargetSelector ts
=
354 case [ t | ql
<- [QL1
.. QLFull
]
355 , t
<- renderTargetSelector ql ts
]
356 of (t
':_
) -> showTargetString
(forgetFileStatus t
')
359 showTargetSelectorKind
:: TargetSelector
-> String
360 showTargetSelectorKind bt
= case bt
of
361 TargetPackage TargetExplicitNamed _ Nothing
-> "package"
362 TargetPackage TargetExplicitNamed _
(Just _
) -> "package:filter"
363 TargetPackage TargetImplicitCwd _ Nothing
-> "cwd-package"
364 TargetPackage TargetImplicitCwd _
(Just _
) -> "cwd-package:filter"
365 TargetPackageNamed _ Nothing
-> "named-package"
366 TargetPackageNamed _
(Just _
) -> "named-package:filter"
367 TargetAllPackages Nothing
-> "package *"
368 TargetAllPackages
(Just _
) -> "package *:filter"
369 TargetComponent _ _ WholeComponent
-> "component"
370 TargetComponent _ _ ModuleTarget
{} -> "module"
371 TargetComponent _ _ FileTarget
{} -> "file"
372 TargetComponentUnknown _ _ WholeComponent
-> "unknown-component"
373 TargetComponentUnknown _ _ ModuleTarget
{} -> "unknown-module"
374 TargetComponentUnknown _ _ FileTarget
{} -> "unknown-file"
377 -- ------------------------------------------------------------
378 -- * Checking if targets exist as files
379 -- ------------------------------------------------------------
381 data TargetStringFileStatus
=
382 TargetStringFileStatus1
String FileStatus
383 | TargetStringFileStatus2
String FileStatus
String
384 | TargetStringFileStatus3
String FileStatus
String String
385 | TargetStringFileStatus4
String String String String
386 | TargetStringFileStatus5
String String String String String
387 | TargetStringFileStatus7
String String String String String String String
388 deriving (Eq
, Ord
, Show)
390 data FileStatus
= FileStatusExistsFile
FilePath -- the canonicalised filepath
391 | FileStatusExistsDir
FilePath -- the canonicalised filepath
392 | FileStatusNotExists
Bool -- does the parent dir exist even?
393 deriving (Eq
, Ord
, Show)
395 noFileStatus
:: FileStatus
396 noFileStatus
= FileStatusNotExists
False
398 getTargetStringFileStatus
:: (Applicative m
, Monad m
) => DirActions m
399 -> TargetString
-> m TargetStringFileStatus
400 getTargetStringFileStatus DirActions
{..} t
=
403 (\f1 -> TargetStringFileStatus1 s1 f1
) <$> fileStatus s1
404 TargetString2 s1 s2
->
405 (\f1 -> TargetStringFileStatus2 s1 f1 s2
) <$> fileStatus s1
406 TargetString3 s1 s2 s3
->
407 (\f1 -> TargetStringFileStatus3 s1 f1 s2 s3
) <$> fileStatus s1
408 TargetString4 s1 s2 s3 s4
->
409 return (TargetStringFileStatus4 s1 s2 s3 s4
)
410 TargetString5 s1 s2 s3 s4 s5
->
411 return (TargetStringFileStatus5 s1 s2 s3 s4 s5
)
412 TargetString7 s1 s2 s3 s4 s5 s6 s7
->
413 return (TargetStringFileStatus7 s1 s2 s3 s4 s5 s6 s7
)
416 fexists
<- doesFileExist f
417 dexists
<- doesDirectoryExist f
419 _ | fexists
-> FileStatusExistsFile
<$> canonicalizePath f
420 | dexists
-> FileStatusExistsDir
<$> canonicalizePath f
421 (d
:_
) -> FileStatusNotExists
<$> doesDirectoryExist d
422 _
-> pure
(FileStatusNotExists
False)
424 forgetFileStatus
:: TargetStringFileStatus
-> TargetString
425 forgetFileStatus t
= case t
of
426 TargetStringFileStatus1 s1 _
-> TargetString1 s1
427 TargetStringFileStatus2 s1 _ s2
-> TargetString2 s1 s2
428 TargetStringFileStatus3 s1 _ s2 s3
-> TargetString3 s1 s2 s3
429 TargetStringFileStatus4 s1 s2 s3 s4
-> TargetString4 s1 s2 s3 s4
430 TargetStringFileStatus5 s1 s2 s3 s4
431 s5
-> TargetString5 s1 s2 s3 s4 s5
432 TargetStringFileStatus7 s1 s2 s3 s4
433 s5 s6 s7
-> TargetString7 s1 s2 s3 s4 s5 s6 s7
435 getFileStatus
:: TargetStringFileStatus
-> Maybe FileStatus
436 getFileStatus
(TargetStringFileStatus1 _ f
) = Just f
437 getFileStatus
(TargetStringFileStatus2 _ f _
) = Just f
438 getFileStatus
(TargetStringFileStatus3 _ f _ _
) = Just f
439 getFileStatus _
= Nothing
441 setFileStatus
:: FileStatus
-> TargetStringFileStatus
-> TargetStringFileStatus
442 setFileStatus f
(TargetStringFileStatus1 s1 _
) = TargetStringFileStatus1 s1 f
443 setFileStatus f
(TargetStringFileStatus2 s1 _ s2
) = TargetStringFileStatus2 s1 f s2
444 setFileStatus f
(TargetStringFileStatus3 s1 _ s2 s3
) = TargetStringFileStatus3 s1 f s2 s3
445 setFileStatus _ t
= t
447 copyFileStatus
:: TargetStringFileStatus
-> TargetStringFileStatus
-> TargetStringFileStatus
448 copyFileStatus src dst
=
449 case getFileStatus src
of
450 Just f
-> setFileStatus f dst
453 -- ------------------------------------------------------------
454 -- * Resolving target strings to target selectors
455 -- ------------------------------------------------------------
458 -- | Given a bunch of user-specified targets, try to resolve what it is they
461 resolveTargetSelectors
:: KnownTargets
462 -> [TargetStringFileStatus
]
463 -> Maybe ComponentKindFilter
464 -> ([TargetSelectorProblem
],
466 -- default local dir target if there's no given target:
467 resolveTargetSelectors
(KnownTargets
{knownPackagesAll
= []}) [] _
=
468 ([TargetSelectorNoTargetsInProject
], [])
470 -- if the component kind filter is just exes, we don't want to suggest "all" as a target.
471 resolveTargetSelectors
(KnownTargets
{knownPackagesPrimary
= []}) [] ckf
=
472 ([TargetSelectorNoTargetsInCwd
(ckf
/= Just ExeKind
) ], [])
474 resolveTargetSelectors
(KnownTargets
{knownPackagesPrimary
}) [] _
=
475 ([], [TargetPackage TargetImplicitCwd pkgids Nothing
])
477 pkgids
= [ pinfoId | KnownPackage
{pinfoId
} <- knownPackagesPrimary
]
479 resolveTargetSelectors knowntargets targetStrs mfilter
=
481 . map (resolveTargetSelector knowntargets mfilter
)
484 resolveTargetSelector
:: KnownTargets
485 -> Maybe ComponentKindFilter
486 -> TargetStringFileStatus
487 -> Either TargetSelectorProblem TargetSelector
488 resolveTargetSelector knowntargets
@KnownTargets
{..} mfilter targetStrStatus
=
489 case findMatch
(matcher targetStrStatus
) of
492 | projectIsEmpty
-> Left TargetSelectorNoTargetsInProject
494 Unambiguous
(TargetPackage TargetImplicitCwd
[] _
)
495 -> Left
(TargetSelectorNoCurrentPackage targetStr
)
497 Unambiguous target
-> Right target
500 | projectIsEmpty
-> Left TargetSelectorNoTargetsInProject
501 |
otherwise -> Left
(classifyMatchErrors errs
)
504 | Just kfilter
<- mfilter
505 , [target
] <- applyKindFilter kfilter targets
-> Right target
507 Ambiguous exactMatch targets
->
508 case disambiguateTargetSelectors
509 matcher targetStrStatus exactMatch
511 Right targets
' -> Left
(TargetSelectorAmbiguous targetStr targets
')
512 Left
((m
, ms
):_
) -> Left
(MatchingInternalError targetStr m ms
)
513 Left
[] -> internalError
"resolveTargetSelector"
515 matcher
= matchTargetSelector knowntargets
517 targetStr
= forgetFileStatus targetStrStatus
519 projectIsEmpty
= null knownPackagesAll
521 classifyMatchErrors errs
522 | Just expectedNE
<- NE
.nonEmpty expected
523 = let (things
, got
:|_
) = NE
.unzip expectedNE
in
524 TargetSelectorExpected targetStr
(NE
.toList things
) got
527 = TargetSelectorNoSuch targetStr nosuch
530 = internalError
$ "classifyMatchErrors: " ++ show errs
532 expected
= [ (thing
, got
)
533 |
(_
, MatchErrorExpected thing got
)
534 <- map (innerErr Nothing
) errs
]
535 -- Trim the list of alternatives by dropping duplicates and
536 -- retaining only at most three most similar (by edit distance) ones.
537 nosuch
= Map
.foldrWithKey genResults
[] $ Map
.fromListWith Set
.union $
538 [ ((inside
, thing
, got
), Set
.fromList alts
)
539 |
(inside
, MatchErrorNoSuch thing got alts
)
540 <- map (innerErr Nothing
) errs
543 genResults
(inside
, thing
, got
) alts acc
= (
549 $ takeWhile distanceLow
550 $ sortBy (comparing
snd)
555 addLevDist
= id &&& restrictedDamerauLevenshteinDistance
558 distanceLow
(_
, dist
) = dist
< length got `
div`
2
562 innerErr _
(MatchErrorIn kind thing m
)
563 = innerErr
(Just
(kind
,thing
)) m
566 applyKindFilter
:: ComponentKindFilter
-> [TargetSelector
] -> [TargetSelector
]
567 applyKindFilter kfilter
= filter go
569 go
(TargetPackage _ _
(Just
filter')) = kfilter
== filter'
570 go
(TargetPackageNamed _
(Just
filter')) = kfilter
== filter'
571 go
(TargetAllPackages
(Just
filter')) = kfilter
== filter'
572 go
(TargetComponent _ cname _
)
573 | CLibName _
<- cname
= kfilter
== LibKind
574 | CFLibName _
<- cname
= kfilter
== FLibKind
575 | CExeName _
<- cname
= kfilter
== ExeKind
576 | CTestName _
<- cname
= kfilter
== TestKind
577 | CBenchName _
<- cname
= kfilter
== BenchKind
580 -- | The various ways that trying to resolve a 'TargetString' to a
581 -- 'TargetSelector' can fail.
583 data TargetSelectorProblem
584 = TargetSelectorExpected TargetString
[String] String
585 -- ^ [expected thing] (actually got)
586 | TargetSelectorNoSuch TargetString
587 [(Maybe (String, String), String, String, [String])]
588 -- ^ [([in thing], no such thing, actually got, alternatives)]
589 | TargetSelectorAmbiguous TargetString
590 [(TargetString
, TargetSelector
)]
592 | MatchingInternalError TargetString TargetSelector
593 [(TargetString
, [TargetSelector
])]
594 | TargetSelectorUnrecognised
String
595 -- ^ Syntax error when trying to parse a target string.
596 | TargetSelectorNoCurrentPackage TargetString
597 | TargetSelectorNoTargetsInCwd
Bool
598 -- ^ bool that flags when it is acceptable to suggest "all" as a target
599 | TargetSelectorNoTargetsInProject
600 | TargetSelectorNoScript TargetString
603 -- | Qualification levels.
604 -- Given the filepath src/F, executable component A, and package foo:
605 data QualLevel
= QL1
-- ^ @src/F@
606 | QL2
-- ^ @foo:src/F | A:src/F@
607 | QL3
-- ^ @foo:A:src/F | exe:A:src/F@
608 | QLFull
-- ^ @pkg:foo:exe:A:file:src/F@
609 deriving (Eq
, Enum
, Show)
611 disambiguateTargetSelectors
612 :: (TargetStringFileStatus
-> Match TargetSelector
)
613 -> TargetStringFileStatus
-> MatchClass
615 -> Either [(TargetSelector
, [(TargetString
, [TargetSelector
])])]
616 [(TargetString
, TargetSelector
)]
617 disambiguateTargetSelectors matcher matchInput exactMatch matchResults
=
618 case partitionEithers results
of
619 (errs
@(_
:_
), _
) -> Left errs
622 -- So, here's the strategy. We take the original match results, and make a
623 -- table of all their renderings at all qualification levels.
624 -- Note there can be multiple renderings at each qualification level.
626 -- Note that renderTargetSelector won't immediately work on any file syntax
627 -- When rendering syntax, the FileStatus is always FileStatusNotExists,
628 -- which will never match on syntaxForm1File!
629 -- Because matchPackageDirectoryPrefix expects a FileStatusExistsFile.
630 -- So we need to copy over the file status from the input
631 -- TargetStringFileStatus, onto the new rendered TargetStringFileStatus
632 matchResultsRenderings
:: [(TargetSelector
, [TargetStringFileStatus
])]
633 matchResultsRenderings
=
634 [ (matchResult
, matchRenderings
)
635 | matchResult
<- matchResults
636 , let matchRenderings
=
637 [ copyFileStatus matchInput rendering
638 | ql
<- [QL1
.. QLFull
]
639 , rendering
<- renderTargetSelector ql matchResult
]
642 -- Of course the point is that we're looking for renderings that are
643 -- unambiguous matches. So we build another memo table of all the matches
644 -- for all of those renderings. So by looking up in this table we can see
645 -- if we've got an unambiguous match.
647 memoisedMatches
:: Map TargetStringFileStatus
(Match TargetSelector
)
649 -- avoid recomputing the main one if it was an exact match
650 (if exactMatch
== Exact
651 then Map
.insert matchInput
(Match Exact
0 matchResults
)
654 -- (matcher rendering) should *always* be a Match! Otherwise we will hit
655 -- the internal error later on.
656 [ (rendering
, matcher rendering
)
657 | rendering
<- concatMap snd matchResultsRenderings
]
659 -- Finally, for each of the match results, we go through all their
660 -- possible renderings (in order of qualification level, though remember
661 -- there can be multiple renderings per level), and find the first one
662 -- that has an unambiguous match.
663 results
:: [Either (TargetSelector
, [(TargetString
, [TargetSelector
])])
664 (TargetString
, TargetSelector
)]
666 [ case findUnambiguous originalMatch matchRenderings
of
667 Just unambiguousRendering
->
668 Right
( forgetFileStatus unambiguousRendering
671 -- This case is an internal error, but we bubble it up and report it
674 , [ (forgetFileStatus rendering
, matches
)
675 | rendering
<- matchRenderings
676 , let Match m _ matches
=
677 memoisedMatches Map
.! rendering
681 |
(originalMatch
, matchRenderings
) <- matchResultsRenderings
]
683 findUnambiguous
:: TargetSelector
684 -> [TargetStringFileStatus
]
685 -> Maybe TargetStringFileStatus
686 findUnambiguous _
[] = Nothing
687 findUnambiguous t
(r
:rs
) =
688 case memoisedMatches Map
.! r
of
689 Match Exact _
[t
'] | t
== t
'
691 Match Exact _ _
-> findUnambiguous t rs
692 Match Unknown _ _
-> findUnambiguous t rs
693 Match Inexact _ _
-> internalError
"Match Inexact"
694 NoMatch _ _
-> internalError
"NoMatch"
696 internalError
:: String -> a
698 error $ "TargetSelector: internal error: " ++ msg
701 -- | Throw an exception with a formatted message if there are any problems.
703 reportTargetSelectorProblems
:: Verbosity
-> [TargetSelectorProblem
] -> IO a
704 reportTargetSelectorProblems verbosity problems
= do
706 case [ str | TargetSelectorUnrecognised str
<- problems
] of
709 die
' verbosity
$ unlines
710 [ "Unrecognised target syntax for '" ++ name
++ "'."
713 case [ (t
, m
, ms
) | MatchingInternalError t m ms
<- problems
] of
715 ((target
, originalMatch
, renderingsAndMatches
):_
) ->
716 die
' verbosity
$ "Internal error in target matching. It should always "
717 ++ "be possible to find a syntax that's sufficiently qualified to "
718 ++ "give an unambiguous match. However when matching '"
719 ++ showTargetString target
++ "' we found "
720 ++ showTargetSelector originalMatch
721 ++ " (" ++ showTargetSelectorKind originalMatch
++ ") which does "
722 ++ "not have an unambiguous syntax. The possible syntax and the "
723 ++ "targets they match are as follows:\n"
725 [ "'" ++ showTargetString rendering
++ "' which matches "
727 [ showTargetSelector match
++
728 " (" ++ showTargetSelectorKind match
++ ")"
730 |
(rendering
, matches
) <- renderingsAndMatches
]
732 case [ (t
, e
, g
) | TargetSelectorExpected t e g
<- problems
] of
735 die
' verbosity
$ unlines
736 [ "Unrecognised target '" ++ showTargetString target
738 ++ "Expected a " ++ intercalate
" or " expected
739 ++ ", rather than '" ++ got
++ "'."
740 |
(target
, expected
, got
) <- targets
]
742 case [ (t
, e
) | TargetSelectorNoSuch t e
<- problems
] of
745 die
' verbosity
$ unlines
746 [ "Unknown target '" ++ showTargetString target
++
750 -> "The " ++ kind
++ " has no "
752 -> "The " ++ kind
++ " " ++ thing
++ " has no "
753 Nothing
-> "There is no ")
754 ++ intercalate
" or " [ mungeThing thing
++ " '" ++ got
++ "'"
755 |
(thing
, got
, _alts
) <- nosuch
' ] ++ "."
756 ++ if null alternatives
then "" else
757 "\nPerhaps you meant " ++ intercalate
";\nor "
758 [ "the " ++ thing
++ " '" ++ intercalate
"' or '" alts
++ "'?"
759 |
(thing
, alts
) <- alternatives
]
760 |
(inside
, nosuch
') <- groupByContainer nosuch
763 |
(thing
,_got
,alts
@(_
:_
)) <- nosuch
' ]
765 |
(target
, nosuch
) <- targets
766 , let groupByContainer
=
767 map (\g
@((inside
,_
,_
,_
):_
) ->
768 (inside
, [ (thing
,got
,alts
)
769 |
(_
,thing
,got
,alts
) <- g
]))
770 . groupBy ((==) `on`
(\(x
,_
,_
,_
) -> x
))
771 . sortBy (compare `on`
(\(x
,_
,_
,_
) -> x
))
774 mungeThing
"file" = "file target"
775 mungeThing thing
= thing
777 case [ (t
, ts
) | TargetSelectorAmbiguous t ts
<- problems
] of
780 die
' verbosity
$ unlines
781 [ "Ambiguous target '" ++ showTargetString target
782 ++ "'. It could be:\n "
783 ++ unlines [ " "++ showTargetString ut
++
784 " (" ++ showTargetSelectorKind bt
++ ")"
786 |
(target
, amb
) <- targets
]
788 case [ t | TargetSelectorNoCurrentPackage t
<- problems
] of
792 "The target '" ++ showTargetString target
++ "' refers to the "
793 ++ "components in the package in the current directory, but there "
794 ++ "is no package in the current directory (or at least not listed "
795 ++ "as part of the project)."
796 --TODO: report a different error if there is a .cabal file but it's
797 -- not a member of the project
799 case [ () | TargetSelectorNoTargetsInCwd
True <- problems
] of
803 "No targets given and there is no package in the current "
804 ++ "directory. Use the target 'all' for all packages in the "
805 ++ "project or specify packages or components by name or location. "
806 ++ "See 'cabal build --help' for more details on target options."
808 case [ () | TargetSelectorNoTargetsInCwd
False <- problems
] of
812 "No targets given and there is no package in the current "
813 ++ "directory. Specify packages or components by name or location. "
814 ++ "See 'cabal build --help' for more details on target options."
816 case [ () | TargetSelectorNoTargetsInProject
<- problems
] of
820 "There is no <pkgname>.cabal package file or cabal.project file. "
821 ++ "To build packages locally you need at minimum a <pkgname>.cabal "
822 ++ "file. You can use 'cabal init' to create one.\n"
824 ++ "For non-trivial projects you will also want a cabal.project "
825 ++ "file in the root directory of your project. This file lists the "
826 ++ "packages in your project and all other build configuration. "
827 ++ "See the Cabal user guide for full details."
829 case [ t | TargetSelectorNoScript t
<- problems
] of
833 "The script '" ++ showTargetString target
++ "' does not exist, "
834 ++ "and only script targets may contain whitespace characters or end "
837 fail "reportTargetSelectorProblems: internal error"
840 ----------------------------------
844 -- | Syntax for the 'TargetSelector': the matcher and renderer
846 data Syntax
= Syntax QualLevel Matcher Renderer
847 | AmbiguousAlternatives Syntax Syntax
848 | ShadowingAlternatives Syntax Syntax
850 type Matcher
= TargetStringFileStatus
-> Match TargetSelector
851 type Renderer
= TargetSelector
-> [TargetStringFileStatus
]
853 foldSyntax
:: (a
-> a
-> a
) -> (a
-> a
-> a
)
854 -> (QualLevel
-> Matcher
-> Renderer
-> a
)
856 foldSyntax ambiguous unambiguous syntax
= go
858 go
(Syntax ql match render
) = syntax ql match render
859 go
(AmbiguousAlternatives a b
) = ambiguous
(go a
) (go b
)
860 go
(ShadowingAlternatives a b
) = unambiguous
(go a
) (go b
)
863 ----------------------------------
864 -- Top level renderer and matcher
867 renderTargetSelector
:: QualLevel
-> TargetSelector
868 -> [TargetStringFileStatus
]
869 renderTargetSelector ql ts
=
872 (\ql
' _ render
-> guard (ql
== ql
') >> render ts
)
875 syntax
= syntaxForms emptyKnownTargets
876 -- don't need known targets for rendering
878 matchTargetSelector
:: KnownTargets
879 -> TargetStringFileStatus
880 -> Match TargetSelector
881 matchTargetSelector knowntargets
= \usertarget
->
884 let ql
= targetQualLevel usertarget
in
887 (\ql
' match _
-> guard (ql
== ql
') >> match usertarget
)
890 syntax
= syntaxForms knowntargets
892 targetQualLevel TargetStringFileStatus1
{} = QL1
893 targetQualLevel TargetStringFileStatus2
{} = QL2
894 targetQualLevel TargetStringFileStatus3
{} = QL3
895 targetQualLevel TargetStringFileStatus4
{} = QLFull
896 targetQualLevel TargetStringFileStatus5
{} = QLFull
897 targetQualLevel TargetStringFileStatus7
{} = QLFull
900 ----------------------------------
904 -- | All the forms of syntax for 'TargetSelector'.
906 syntaxForms
:: KnownTargets
-> Syntax
907 syntaxForms KnownTargets
{
908 knownPackagesAll
= pinfo
,
909 knownPackagesPrimary
= ppinfo
,
910 knownComponentsAll
= cinfo
,
911 knownComponentsPrimary
= pcinfo
,
912 knownComponentsOther
= ocinfo
914 -- The various forms of syntax here are ambiguous in many cases.
915 -- Our policy is by default we expose that ambiguity and report
916 -- ambiguous matches. In certain cases we override the ambiguity
917 -- by having some forms shadow others.
919 -- We make modules shadow files because module name "Q" clashes
920 -- with file "Q" with no extension but these refer to the same
921 -- thing anyway so it's not a useful ambiguity. Other cases are
922 -- not ambiguous like "Q" vs "Q.hs" or "Data.Q" vs "Data/Q".
924 ambiguousAlternatives
925 -- convenient single-component forms
926 [ shadowingAlternatives
927 [ ambiguousAlternatives
929 , syntaxForm1Filter ppinfo
930 , shadowingAlternatives
931 [ syntaxForm1Component pcinfo
932 , syntaxForm1Package pinfo
935 , syntaxForm1Component ocinfo
936 , syntaxForm1Module cinfo
937 , syntaxForm1File pinfo
940 -- two-component partially qualified forms
941 -- fully qualified form for 'all'
943 , syntaxForm2AllFilter
944 , syntaxForm2NamespacePackage pinfo
945 , syntaxForm2PackageComponent pinfo
946 , syntaxForm2PackageFilter pinfo
947 , syntaxForm2KindComponent cinfo
948 , shadowingAlternatives
949 [ syntaxForm2PackageModule pinfo
950 , syntaxForm2PackageFile pinfo
952 , shadowingAlternatives
953 [ syntaxForm2ComponentModule cinfo
954 , syntaxForm2ComponentFile cinfo
957 -- rarely used partially qualified forms
958 , syntaxForm3PackageKindComponent pinfo
959 , shadowingAlternatives
960 [ syntaxForm3PackageComponentModule pinfo
961 , syntaxForm3PackageComponentFile pinfo
963 , shadowingAlternatives
964 [ syntaxForm3KindComponentModule cinfo
965 , syntaxForm3KindComponentFile cinfo
967 , syntaxForm3NamespacePackageFilter pinfo
969 -- fully-qualified forms for all and cwd with filter
970 , syntaxForm3MetaAllFilter
971 , syntaxForm3MetaCwdFilter ppinfo
973 -- fully-qualified form for package and package with filter
974 , syntaxForm3MetaNamespacePackage pinfo
975 , syntaxForm4MetaNamespacePackageFilter pinfo
977 -- fully-qualified forms for component, module and file
978 , syntaxForm5MetaNamespacePackageKindComponent pinfo
979 , syntaxForm7MetaNamespacePackageKindComponentNamespaceModule pinfo
980 , syntaxForm7MetaNamespacePackageKindComponentNamespaceFile pinfo
983 ambiguousAlternatives
= Prelude
.foldr1 AmbiguousAlternatives
984 shadowingAlternatives
= Prelude
.foldr1 ShadowingAlternatives
987 -- | Syntax: "all" to select all packages in the project
991 syntaxForm1All
:: Syntax
993 syntaxForm1 render
$ \str1 _fstatus1
-> do
995 return (TargetAllPackages Nothing
)
997 render
(TargetAllPackages Nothing
) =
998 [TargetStringFileStatus1
"all" noFileStatus
]
1003 -- > cabal build tests
1005 syntaxForm1Filter
:: [KnownPackage
] -> Syntax
1006 syntaxForm1Filter ps
=
1007 syntaxForm1 render
$ \str1 _fstatus1
-> do
1008 kfilter
<- matchComponentKindFilter str1
1009 return (TargetPackage TargetImplicitCwd pids
(Just kfilter
))
1011 pids
= [ pinfoId | KnownPackage
{pinfoId
} <- ps
]
1012 render
(TargetPackage TargetImplicitCwd _
(Just kfilter
)) =
1013 [TargetStringFileStatus1
(dispF kfilter
) noFileStatus
]
1017 -- | Syntax: package (name, dir or file)
1019 -- > cabal build foo
1020 -- > cabal build ../bar ../bar/bar.cabal
1022 syntaxForm1Package
:: [KnownPackage
] -> Syntax
1023 syntaxForm1Package pinfo
=
1024 syntaxForm1 render
$ \str1 fstatus1
-> do
1025 guardPackage str1 fstatus1
1026 p
<- matchPackage pinfo str1 fstatus1
1028 KnownPackage
{pinfoId
} ->
1029 return (TargetPackage TargetExplicitNamed
[pinfoId
] Nothing
)
1030 KnownPackageName pn
->
1031 return (TargetPackageNamed pn Nothing
)
1033 render
(TargetPackage TargetExplicitNamed
[p
] Nothing
) =
1034 [TargetStringFileStatus1
(dispP p
) noFileStatus
]
1035 render
(TargetPackageNamed pn Nothing
) =
1036 [TargetStringFileStatus1
(dispPN pn
) noFileStatus
]
1039 -- | Syntax: component
1041 -- > cabal build foo
1043 syntaxForm1Component
:: [KnownComponent
] -> Syntax
1044 syntaxForm1Component cs
=
1045 syntaxForm1 render
$ \str1 _fstatus1
-> do
1046 guardComponentName str1
1047 c
<- matchComponentName cs str1
1048 return (TargetComponent
(cinfoPackageId c
) (cinfoName c
) WholeComponent
)
1050 render
(TargetComponent p c WholeComponent
) =
1051 [TargetStringFileStatus1
(dispC p c
) noFileStatus
]
1056 -- > cabal build Data.Foo
1058 syntaxForm1Module
:: [KnownComponent
] -> Syntax
1059 syntaxForm1Module cs
=
1060 syntaxForm1 render
$ \str1 _fstatus1
-> do
1061 guardModuleName str1
1062 let ms
= [ (m
,c
) | c
<- cs
, m
<- cinfoModules c
]
1063 (m
,c
) <- matchModuleNameAnd ms str1
1064 return (TargetComponent
(cinfoPackageId c
) (cinfoName c
) (ModuleTarget m
))
1066 render
(TargetComponent _p _c
(ModuleTarget m
)) =
1067 [TargetStringFileStatus1
(dispM m
) noFileStatus
]
1070 -- | Syntax: file name
1072 -- > cabal build Data/Foo.hs bar/Main.hsc
1074 syntaxForm1File
:: [KnownPackage
] -> Syntax
1075 syntaxForm1File ps
=
1076 -- Note there's a bit of an inconsistency here vs the other syntax forms
1077 -- for files. For the single-part syntax the target has to point to a file
1078 -- that exists (due to our use of matchPackageDirectoryPrefix), whereas for
1079 -- all the other forms we don't require that.
1080 syntaxForm1 render
$ \str1 fstatus1
->
1081 expecting
"file" str1
$ do
1082 (pkgfile
, ~KnownPackage
{pinfoId
, pinfoComponents
})
1083 -- always returns the KnownPackage case
1084 <- matchPackageDirectoryPrefix ps fstatus1
1085 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1086 (filepath
, c
) <- matchComponentFile pinfoComponents pkgfile
1087 return (TargetComponent pinfoId
(cinfoName c
) (FileTarget filepath
))
1089 render
(TargetComponent _p _c
(FileTarget f
)) =
1090 [TargetStringFileStatus1 f noFileStatus
]
1097 -- > cabal build :all
1099 syntaxForm2MetaAll
:: Syntax
1100 syntaxForm2MetaAll
=
1101 syntaxForm2 render
$ \str1 _fstatus1 str2
-> do
1102 guardNamespaceMeta str1
1104 return (TargetAllPackages Nothing
)
1106 render
(TargetAllPackages Nothing
) =
1107 [TargetStringFileStatus2
"" noFileStatus
"all"]
1110 -- | Syntax: all : filer
1112 -- > cabal build all:tests
1114 syntaxForm2AllFilter
:: Syntax
1115 syntaxForm2AllFilter
=
1116 syntaxForm2 render
$ \str1 _fstatus1 str2
-> do
1118 kfilter
<- matchComponentKindFilter str2
1119 return (TargetAllPackages
(Just kfilter
))
1121 render
(TargetAllPackages
(Just kfilter
)) =
1122 [TargetStringFileStatus2
"all" noFileStatus
(dispF kfilter
)]
1125 -- | Syntax: package : filer
1127 -- > cabal build foo:tests
1129 syntaxForm2PackageFilter
:: [KnownPackage
] -> Syntax
1130 syntaxForm2PackageFilter ps
=
1131 syntaxForm2 render
$ \str1 fstatus1 str2
-> do
1132 guardPackage str1 fstatus1
1133 p
<- matchPackage ps str1 fstatus1
1134 kfilter
<- matchComponentKindFilter str2
1136 KnownPackage
{pinfoId
} ->
1137 return (TargetPackage TargetExplicitNamed
[pinfoId
] (Just kfilter
))
1138 KnownPackageName pn
->
1139 return (TargetPackageNamed pn
(Just kfilter
))
1141 render
(TargetPackage TargetExplicitNamed
[p
] (Just kfilter
)) =
1142 [TargetStringFileStatus2
(dispP p
) noFileStatus
(dispF kfilter
)]
1143 render
(TargetPackageNamed pn
(Just kfilter
)) =
1144 [TargetStringFileStatus2
(dispPN pn
) noFileStatus
(dispF kfilter
)]
1147 -- | Syntax: pkg : package name
1149 -- > cabal build pkg:foo
1151 syntaxForm2NamespacePackage
:: [KnownPackage
] -> Syntax
1152 syntaxForm2NamespacePackage pinfo
=
1153 syntaxForm2 render
$ \str1 _fstatus1 str2
-> do
1154 guardNamespacePackage str1
1155 guardPackageName str2
1156 p
<- matchPackage pinfo str2 noFileStatus
1158 KnownPackage
{pinfoId
} ->
1159 return (TargetPackage TargetExplicitNamed
[pinfoId
] Nothing
)
1160 KnownPackageName pn
->
1161 return (TargetPackageNamed pn Nothing
)
1163 render
(TargetPackage TargetExplicitNamed
[p
] Nothing
) =
1164 [TargetStringFileStatus2
"pkg" noFileStatus
(dispP p
)]
1165 render
(TargetPackageNamed pn Nothing
) =
1166 [TargetStringFileStatus2
"pkg" noFileStatus
(dispPN pn
)]
1169 -- | Syntax: package : component
1171 -- > cabal build foo:foo
1172 -- > cabal build ./foo:foo
1173 -- > cabal build ./foo.cabal:foo
1175 syntaxForm2PackageComponent
:: [KnownPackage
] -> Syntax
1176 syntaxForm2PackageComponent ps
=
1177 syntaxForm2 render
$ \str1 fstatus1 str2
-> do
1178 guardPackage str1 fstatus1
1179 guardComponentName str2
1180 p
<- matchPackage ps str1 fstatus1
1182 KnownPackage
{pinfoId
, pinfoComponents
} ->
1183 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1184 c
<- matchComponentName pinfoComponents str2
1185 return (TargetComponent pinfoId
(cinfoName c
) WholeComponent
)
1186 --TODO: the error here ought to say there's no component by that name in
1187 -- this package, and name the package
1188 KnownPackageName pn
->
1189 let cn
= mkUnqualComponentName str2
in
1190 return (TargetComponentUnknown pn
(Left cn
) WholeComponent
)
1192 render
(TargetComponent p c WholeComponent
) =
1193 [TargetStringFileStatus2
(dispP p
) noFileStatus
(dispC p c
)]
1194 render
(TargetComponentUnknown pn
(Left cn
) WholeComponent
) =
1195 [TargetStringFileStatus2
(dispPN pn
) noFileStatus
(prettyShow cn
)]
1198 -- | Syntax: namespace : component
1200 -- > cabal build lib:foo exe:foo
1202 syntaxForm2KindComponent
:: [KnownComponent
] -> Syntax
1203 syntaxForm2KindComponent cs
=
1204 syntaxForm2 render
$ \str1 _fstatus1 str2
-> do
1205 ckind
<- matchComponentKind str1
1206 guardComponentName str2
1207 c
<- matchComponentKindAndName cs ckind str2
1208 return (TargetComponent
(cinfoPackageId c
) (cinfoName c
) WholeComponent
)
1210 render
(TargetComponent p c WholeComponent
) =
1211 [TargetStringFileStatus2
(dispCK c
) noFileStatus
(dispC p c
)]
1214 -- | Syntax: package : module
1216 -- > cabal build foo:Data.Foo
1217 -- > cabal build ./foo:Data.Foo
1218 -- > cabal build ./foo.cabal:Data.Foo
1220 syntaxForm2PackageModule
:: [KnownPackage
] -> Syntax
1221 syntaxForm2PackageModule ps
=
1222 syntaxForm2 render
$ \str1 fstatus1 str2
-> do
1223 guardPackage str1 fstatus1
1224 guardModuleName str2
1225 p
<- matchPackage ps str1 fstatus1
1227 KnownPackage
{pinfoId
, pinfoComponents
} ->
1228 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1229 let ms
= [ (m
,c
) | c
<- pinfoComponents
, m
<- cinfoModules c
]
1230 (m
,c
) <- matchModuleNameAnd ms str2
1231 return (TargetComponent pinfoId
(cinfoName c
) (ModuleTarget m
))
1232 KnownPackageName pn
-> do
1233 m
<- matchModuleNameUnknown str2
1234 -- We assume the primary library component of the package:
1235 return (TargetComponentUnknown pn
(Right
$ CLibName LMainLibName
) (ModuleTarget m
))
1237 render
(TargetComponent p _c
(ModuleTarget m
)) =
1238 [TargetStringFileStatus2
(dispP p
) noFileStatus
(dispM m
)]
1241 -- | Syntax: component : module
1243 -- > cabal build foo:Data.Foo
1245 syntaxForm2ComponentModule
:: [KnownComponent
] -> Syntax
1246 syntaxForm2ComponentModule cs
=
1247 syntaxForm2 render
$ \str1 _fstatus1 str2
-> do
1248 guardComponentName str1
1249 guardModuleName str2
1250 c
<- matchComponentName cs str1
1251 orNoThingIn
"component" (cinfoStrName c
) $ do
1252 let ms
= cinfoModules c
1253 m
<- matchModuleName ms str2
1254 return (TargetComponent
(cinfoPackageId c
) (cinfoName c
)
1257 render
(TargetComponent p c
(ModuleTarget m
)) =
1258 [TargetStringFileStatus2
(dispC p c
) noFileStatus
(dispM m
)]
1261 -- | Syntax: package : filename
1263 -- > cabal build foo:Data/Foo.hs
1264 -- > cabal build ./foo:Data/Foo.hs
1265 -- > cabal build ./foo.cabal:Data/Foo.hs
1267 syntaxForm2PackageFile
:: [KnownPackage
] -> Syntax
1268 syntaxForm2PackageFile ps
=
1269 syntaxForm2 render
$ \str1 fstatus1 str2
-> do
1270 guardPackage str1 fstatus1
1271 p
<- matchPackage ps str1 fstatus1
1273 KnownPackage
{pinfoId
, pinfoComponents
} ->
1274 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1275 (filepath
, c
) <- matchComponentFile pinfoComponents str2
1276 return (TargetComponent pinfoId
(cinfoName c
) (FileTarget filepath
))
1277 KnownPackageName pn
->
1278 let filepath
= str2
in
1279 -- We assume the primary library component of the package:
1280 return (TargetComponentUnknown pn
(Right
$ CLibName LMainLibName
) (FileTarget filepath
))
1282 render
(TargetComponent p _c
(FileTarget f
)) =
1283 [TargetStringFileStatus2
(dispP p
) noFileStatus f
]
1286 -- | Syntax: component : filename
1288 -- > cabal build foo:Data/Foo.hs
1290 syntaxForm2ComponentFile
:: [KnownComponent
] -> Syntax
1291 syntaxForm2ComponentFile cs
=
1292 syntaxForm2 render
$ \str1 _fstatus1 str2
-> do
1293 guardComponentName str1
1294 c
<- matchComponentName cs str1
1295 orNoThingIn
"component" (cinfoStrName c
) $ do
1296 (filepath
, _
) <- matchComponentFile
[c
] str2
1297 return (TargetComponent
(cinfoPackageId c
) (cinfoName c
)
1298 (FileTarget filepath
))
1300 render
(TargetComponent p c
(FileTarget f
)) =
1301 [TargetStringFileStatus2
(dispC p c
) noFileStatus f
]
1306 -- | Syntax: :all : filter
1308 -- > cabal build :all:tests
1310 syntaxForm3MetaAllFilter
:: Syntax
1311 syntaxForm3MetaAllFilter
=
1312 syntaxForm3 render
$ \str1 _fstatus1 str2 str3
-> do
1313 guardNamespaceMeta str1
1315 kfilter
<- matchComponentKindFilter str3
1316 return (TargetAllPackages
(Just kfilter
))
1318 render
(TargetAllPackages
(Just kfilter
)) =
1319 [TargetStringFileStatus3
"" noFileStatus
"all" (dispF kfilter
)]
1322 syntaxForm3MetaCwdFilter
:: [KnownPackage
] -> Syntax
1323 syntaxForm3MetaCwdFilter ps
=
1324 syntaxForm3 render
$ \str1 _fstatus1 str2 str3
-> do
1325 guardNamespaceMeta str1
1326 guardNamespaceCwd str2
1327 kfilter
<- matchComponentKindFilter str3
1328 return (TargetPackage TargetImplicitCwd pids
(Just kfilter
))
1330 pids
= [ pinfoId | KnownPackage
{pinfoId
} <- ps
]
1331 render
(TargetPackage TargetImplicitCwd _
(Just kfilter
)) =
1332 [TargetStringFileStatus3
"" noFileStatus
"cwd" (dispF kfilter
)]
1335 -- | Syntax: :pkg : package name
1337 -- > cabal build :pkg:foo
1339 syntaxForm3MetaNamespacePackage
:: [KnownPackage
] -> Syntax
1340 syntaxForm3MetaNamespacePackage pinfo
=
1341 syntaxForm3 render
$ \str1 _fstatus1 str2 str3
-> do
1342 guardNamespaceMeta str1
1343 guardNamespacePackage str2
1344 guardPackageName str3
1345 p
<- matchPackage pinfo str3 noFileStatus
1347 KnownPackage
{pinfoId
} ->
1348 return (TargetPackage TargetExplicitNamed
[pinfoId
] Nothing
)
1349 KnownPackageName pn
->
1350 return (TargetPackageNamed pn Nothing
)
1352 render
(TargetPackage TargetExplicitNamed
[p
] Nothing
) =
1353 [TargetStringFileStatus3
"" noFileStatus
"pkg" (dispP p
)]
1354 render
(TargetPackageNamed pn Nothing
) =
1355 [TargetStringFileStatus3
"" noFileStatus
"pkg" (dispPN pn
)]
1358 -- | Syntax: package : namespace : component
1360 -- > cabal build foo:lib:foo
1361 -- > cabal build foo/:lib:foo
1362 -- > cabal build foo.cabal:lib:foo
1364 syntaxForm3PackageKindComponent
:: [KnownPackage
] -> Syntax
1365 syntaxForm3PackageKindComponent ps
=
1366 syntaxForm3 render
$ \str1 fstatus1 str2 str3
-> do
1367 guardPackage str1 fstatus1
1368 ckind
<- matchComponentKind str2
1369 guardComponentName str3
1370 p
<- matchPackage ps str1 fstatus1
1372 KnownPackage
{pinfoId
, pinfoComponents
} ->
1373 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1374 c
<- matchComponentKindAndName pinfoComponents ckind str3
1375 return (TargetComponent pinfoId
(cinfoName c
) WholeComponent
)
1376 KnownPackageName pn
->
1377 let cn
= mkComponentName pn ckind
(mkUnqualComponentName str3
) in
1378 return (TargetComponentUnknown pn
(Right cn
) WholeComponent
)
1380 render
(TargetComponent p c WholeComponent
) =
1381 [TargetStringFileStatus3
(dispP p
) noFileStatus
(dispCK c
) (dispC p c
)]
1382 render
(TargetComponentUnknown pn
(Right c
) WholeComponent
) =
1383 [TargetStringFileStatus3
(dispPN pn
) noFileStatus
(dispCK c
) (dispC
' pn c
)]
1386 -- | Syntax: package : component : module
1388 -- > cabal build foo:foo:Data.Foo
1389 -- > cabal build foo/:foo:Data.Foo
1390 -- > cabal build foo.cabal:foo:Data.Foo
1392 syntaxForm3PackageComponentModule
:: [KnownPackage
] -> Syntax
1393 syntaxForm3PackageComponentModule ps
=
1394 syntaxForm3 render
$ \str1 fstatus1 str2 str3
-> do
1395 guardPackage str1 fstatus1
1396 guardComponentName str2
1397 guardModuleName str3
1398 p
<- matchPackage ps str1 fstatus1
1400 KnownPackage
{pinfoId
, pinfoComponents
} ->
1401 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1402 c
<- matchComponentName pinfoComponents str2
1403 orNoThingIn
"component" (cinfoStrName c
) $ do
1404 let ms
= cinfoModules c
1405 m
<- matchModuleName ms str3
1406 return (TargetComponent pinfoId
(cinfoName c
) (ModuleTarget m
))
1407 KnownPackageName pn
-> do
1408 let cn
= mkUnqualComponentName str2
1409 m
<- matchModuleNameUnknown str3
1410 return (TargetComponentUnknown pn
(Left cn
) (ModuleTarget m
))
1412 render
(TargetComponent p c
(ModuleTarget m
)) =
1413 [TargetStringFileStatus3
(dispP p
) noFileStatus
(dispC p c
) (dispM m
)]
1414 render
(TargetComponentUnknown pn
(Left c
) (ModuleTarget m
)) =
1415 [TargetStringFileStatus3
(dispPN pn
) noFileStatus
(dispCN c
) (dispM m
)]
1418 -- | Syntax: namespace : component : module
1420 -- > cabal build lib:foo:Data.Foo
1422 syntaxForm3KindComponentModule
:: [KnownComponent
] -> Syntax
1423 syntaxForm3KindComponentModule cs
=
1424 syntaxForm3 render
$ \str1 _fstatus1 str2 str3
-> do
1425 ckind
<- matchComponentKind str1
1426 guardComponentName str2
1427 guardModuleName str3
1428 c
<- matchComponentKindAndName cs ckind str2
1429 orNoThingIn
"component" (cinfoStrName c
) $ do
1430 let ms
= cinfoModules c
1431 m
<- matchModuleName ms str3
1432 return (TargetComponent
(cinfoPackageId c
) (cinfoName c
)
1435 render
(TargetComponent p c
(ModuleTarget m
)) =
1436 [TargetStringFileStatus3
(dispCK c
) noFileStatus
(dispC p c
) (dispM m
)]
1439 -- | Syntax: package : component : filename
1441 -- > cabal build foo:foo:Data/Foo.hs
1442 -- > cabal build foo/:foo:Data/Foo.hs
1443 -- > cabal build foo.cabal:foo:Data/Foo.hs
1445 syntaxForm3PackageComponentFile
:: [KnownPackage
] -> Syntax
1446 syntaxForm3PackageComponentFile ps
=
1447 syntaxForm3 render
$ \str1 fstatus1 str2 str3
-> do
1448 guardPackage str1 fstatus1
1449 guardComponentName str2
1450 p
<- matchPackage ps str1 fstatus1
1452 KnownPackage
{pinfoId
, pinfoComponents
} ->
1453 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1454 c
<- matchComponentName pinfoComponents str2
1455 orNoThingIn
"component" (cinfoStrName c
) $ do
1456 (filepath
, _
) <- matchComponentFile
[c
] str3
1457 return (TargetComponent pinfoId
(cinfoName c
) (FileTarget filepath
))
1458 KnownPackageName pn
->
1459 let cn
= mkUnqualComponentName str2
1461 return (TargetComponentUnknown pn
(Left cn
) (FileTarget filepath
))
1463 render
(TargetComponent p c
(FileTarget f
)) =
1464 [TargetStringFileStatus3
(dispP p
) noFileStatus
(dispC p c
) f
]
1465 render
(TargetComponentUnknown pn
(Left c
) (FileTarget f
)) =
1466 [TargetStringFileStatus3
(dispPN pn
) noFileStatus
(dispCN c
) f
]
1469 -- | Syntax: namespace : component : filename
1471 -- > cabal build lib:foo:Data/Foo.hs
1473 syntaxForm3KindComponentFile
:: [KnownComponent
] -> Syntax
1474 syntaxForm3KindComponentFile cs
=
1475 syntaxForm3 render
$ \str1 _fstatus1 str2 str3
-> do
1476 ckind
<- matchComponentKind str1
1477 guardComponentName str2
1478 c
<- matchComponentKindAndName cs ckind str2
1479 orNoThingIn
"component" (cinfoStrName c
) $ do
1480 (filepath
, _
) <- matchComponentFile
[c
] str3
1481 return (TargetComponent
(cinfoPackageId c
) (cinfoName c
)
1482 (FileTarget filepath
))
1484 render
(TargetComponent p c
(FileTarget f
)) =
1485 [TargetStringFileStatus3
(dispCK c
) noFileStatus
(dispC p c
) f
]
1488 syntaxForm3NamespacePackageFilter
:: [KnownPackage
] -> Syntax
1489 syntaxForm3NamespacePackageFilter ps
=
1490 syntaxForm3 render
$ \str1 _fstatus1 str2 str3
-> do
1491 guardNamespacePackage str1
1492 guardPackageName str2
1493 p
<- matchPackage ps str2 noFileStatus
1494 kfilter
<- matchComponentKindFilter str3
1496 KnownPackage
{pinfoId
} ->
1497 return (TargetPackage TargetExplicitNamed
[pinfoId
] (Just kfilter
))
1498 KnownPackageName pn
->
1499 return (TargetPackageNamed pn
(Just kfilter
))
1501 render
(TargetPackage TargetExplicitNamed
[p
] (Just kfilter
)) =
1502 [TargetStringFileStatus3
"pkg" noFileStatus
(dispP p
) (dispF kfilter
)]
1503 render
(TargetPackageNamed pn
(Just kfilter
)) =
1504 [TargetStringFileStatus3
"pkg" noFileStatus
(dispPN pn
) (dispF kfilter
)]
1509 syntaxForm4MetaNamespacePackageFilter
:: [KnownPackage
] -> Syntax
1510 syntaxForm4MetaNamespacePackageFilter ps
=
1511 syntaxForm4 render
$ \str1 str2 str3 str4
-> do
1512 guardNamespaceMeta str1
1513 guardNamespacePackage str2
1514 guardPackageName str3
1515 p
<- matchPackage ps str3 noFileStatus
1516 kfilter
<- matchComponentKindFilter str4
1518 KnownPackage
{pinfoId
} ->
1519 return (TargetPackage TargetExplicitNamed
[pinfoId
] (Just kfilter
))
1520 KnownPackageName pn
->
1521 return (TargetPackageNamed pn
(Just kfilter
))
1523 render
(TargetPackage TargetExplicitNamed
[p
] (Just kfilter
)) =
1524 [TargetStringFileStatus4
"" "pkg" (dispP p
) (dispF kfilter
)]
1525 render
(TargetPackageNamed pn
(Just kfilter
)) =
1526 [TargetStringFileStatus4
"" "pkg" (dispPN pn
) (dispF kfilter
)]
1529 -- | Syntax: :pkg : package : namespace : component
1531 -- > cabal build :pkg:foo:lib:foo
1533 syntaxForm5MetaNamespacePackageKindComponent
:: [KnownPackage
] -> Syntax
1534 syntaxForm5MetaNamespacePackageKindComponent ps
=
1535 syntaxForm5 render
$ \str1 str2 str3 str4 str5
-> do
1536 guardNamespaceMeta str1
1537 guardNamespacePackage str2
1538 guardPackageName str3
1539 ckind
<- matchComponentKind str4
1540 guardComponentName str5
1541 p
<- matchPackage ps str3 noFileStatus
1543 KnownPackage
{pinfoId
, pinfoComponents
} ->
1544 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1545 c
<- matchComponentKindAndName pinfoComponents ckind str5
1546 return (TargetComponent pinfoId
(cinfoName c
) WholeComponent
)
1547 KnownPackageName pn
->
1548 let cn
= mkComponentName pn ckind
(mkUnqualComponentName str5
) in
1549 return (TargetComponentUnknown pn
(Right cn
) WholeComponent
)
1551 render
(TargetComponent p c WholeComponent
) =
1552 [TargetStringFileStatus5
"" "pkg" (dispP p
) (dispCK c
) (dispC p c
)]
1553 render
(TargetComponentUnknown pn
(Right c
) WholeComponent
) =
1554 [TargetStringFileStatus5
"" "pkg" (dispPN pn
) (dispCK c
) (dispC
' pn c
)]
1557 -- | Syntax: :pkg : package : namespace : component : module : module
1559 -- > cabal build :pkg:foo:lib:foo:module:Data.Foo
1561 syntaxForm7MetaNamespacePackageKindComponentNamespaceModule
1562 :: [KnownPackage
] -> Syntax
1563 syntaxForm7MetaNamespacePackageKindComponentNamespaceModule ps
=
1564 syntaxForm7 render
$ \str1 str2 str3 str4 str5 str6 str7
-> do
1565 guardNamespaceMeta str1
1566 guardNamespacePackage str2
1567 guardPackageName str3
1568 ckind
<- matchComponentKind str4
1569 guardComponentName str5
1570 guardNamespaceModule str6
1571 p
<- matchPackage ps str3 noFileStatus
1573 KnownPackage
{pinfoId
, pinfoComponents
} ->
1574 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1575 c
<- matchComponentKindAndName pinfoComponents ckind str5
1576 orNoThingIn
"component" (cinfoStrName c
) $ do
1577 let ms
= cinfoModules c
1578 m
<- matchModuleName ms str7
1579 return (TargetComponent pinfoId
(cinfoName c
) (ModuleTarget m
))
1580 KnownPackageName pn
-> do
1581 let cn
= mkComponentName pn ckind
(mkUnqualComponentName str2
)
1582 m
<- matchModuleNameUnknown str7
1583 return (TargetComponentUnknown pn
(Right cn
) (ModuleTarget m
))
1585 render
(TargetComponent p c
(ModuleTarget m
)) =
1586 [TargetStringFileStatus7
"" "pkg" (dispP p
)
1587 (dispCK c
) (dispC p c
)
1589 render
(TargetComponentUnknown pn
(Right c
) (ModuleTarget m
)) =
1590 [TargetStringFileStatus7
"" "pkg" (dispPN pn
)
1591 (dispCK c
) (dispC
' pn c
)
1595 -- | Syntax: :pkg : package : namespace : component : file : filename
1597 -- > cabal build :pkg:foo:lib:foo:file:Data/Foo.hs
1599 syntaxForm7MetaNamespacePackageKindComponentNamespaceFile
1600 :: [KnownPackage
] -> Syntax
1601 syntaxForm7MetaNamespacePackageKindComponentNamespaceFile ps
=
1602 syntaxForm7 render
$ \str1 str2 str3 str4 str5 str6 str7
-> do
1603 guardNamespaceMeta str1
1604 guardNamespacePackage str2
1605 guardPackageName str3
1606 ckind
<- matchComponentKind str4
1607 guardComponentName str5
1608 guardNamespaceFile str6
1609 p
<- matchPackage ps str3 noFileStatus
1611 KnownPackage
{pinfoId
, pinfoComponents
} ->
1612 orNoThingIn
"package" (prettyShow
(packageName pinfoId
)) $ do
1613 c
<- matchComponentKindAndName pinfoComponents ckind str5
1614 orNoThingIn
"component" (cinfoStrName c
) $ do
1615 (filepath
,_
) <- matchComponentFile
[c
] str7
1616 return (TargetComponent pinfoId
(cinfoName c
) (FileTarget filepath
))
1617 KnownPackageName pn
->
1618 let cn
= mkComponentName pn ckind
(mkUnqualComponentName str5
)
1620 return (TargetComponentUnknown pn
(Right cn
) (FileTarget filepath
))
1622 render
(TargetComponent p c
(FileTarget f
)) =
1623 [TargetStringFileStatus7
"" "pkg" (dispP p
)
1624 (dispCK c
) (dispC p c
)
1626 render
(TargetComponentUnknown pn
(Right c
) (FileTarget f
)) =
1627 [TargetStringFileStatus7
"" "pkg" (dispPN pn
)
1628 (dispCK c
) (dispC
' pn c
)
1633 ---------------------------------------
1637 type Match1
= String -> FileStatus
-> Match TargetSelector
1638 type Match2
= String -> FileStatus
-> String
1639 -> Match TargetSelector
1640 type Match3
= String -> FileStatus
-> String -> String
1641 -> Match TargetSelector
1642 type Match4
= String -> String -> String -> String
1643 -> Match TargetSelector
1644 type Match5
= String -> String -> String -> String -> String
1645 -> Match TargetSelector
1646 type Match7
= String -> String -> String -> String -> String -> String -> String
1647 -> Match TargetSelector
1649 syntaxForm1
:: Renderer
-> Match1
-> Syntax
1650 syntaxForm2
:: Renderer
-> Match2
-> Syntax
1651 syntaxForm3
:: Renderer
-> Match3
-> Syntax
1652 syntaxForm4
:: Renderer
-> Match4
-> Syntax
1653 syntaxForm5
:: Renderer
-> Match5
-> Syntax
1654 syntaxForm7
:: Renderer
-> Match7
-> Syntax
1656 syntaxForm1 render f
=
1657 Syntax QL1 match render
1659 match
= \(TargetStringFileStatus1 str1 fstatus1
) ->
1662 syntaxForm2 render f
=
1663 Syntax QL2 match render
1665 match
= \(TargetStringFileStatus2 str1 fstatus1 str2
) ->
1666 f str1 fstatus1 str2
1668 syntaxForm3 render f
=
1669 Syntax QL3 match render
1671 match
= \(TargetStringFileStatus3 str1 fstatus1 str2 str3
) ->
1672 f str1 fstatus1 str2 str3
1674 syntaxForm4 render f
=
1675 Syntax QLFull match render
1677 match
(TargetStringFileStatus4 str1 str2 str3 str4
)
1678 = f str1 str2 str3 str4
1681 syntaxForm5 render f
=
1682 Syntax QLFull match render
1684 match
(TargetStringFileStatus5 str1 str2 str3 str4 str5
)
1685 = f str1 str2 str3 str4 str5
1688 syntaxForm7 render f
=
1689 Syntax QLFull match render
1691 match
(TargetStringFileStatus7 str1 str2 str3 str4 str5 str6 str7
)
1692 = f str1 str2 str3 str4 str5 str6 str7
1695 dispP
:: Package p
=> p
-> String
1696 dispP
= prettyShow
. packageName
1698 dispPN
:: PackageName
-> String
1701 dispC
:: PackageId
-> ComponentName
-> String
1702 dispC
= componentStringName
. packageName
1704 dispC
' :: PackageName
-> ComponentName
-> String
1705 dispC
' = componentStringName
1707 dispCN
:: UnqualComponentName
-> String
1710 dispK
:: ComponentKind
-> String
1711 dispK
= showComponentKindShort
1713 dispCK
:: ComponentName
-> String
1714 dispCK
= dispK
. componentKind
1716 dispF
:: ComponentKind
-> String
1717 dispF
= showComponentKindFilterShort
1719 dispM
:: ModuleName
-> String
1723 -------------------------------
1724 -- Package and component info
1727 data KnownTargets
= KnownTargets
{
1728 knownPackagesAll
:: [KnownPackage
],
1729 knownPackagesPrimary
:: [KnownPackage
],
1730 knownPackagesOther
:: [KnownPackage
],
1731 knownComponentsAll
:: [KnownComponent
],
1732 knownComponentsPrimary
:: [KnownComponent
],
1733 knownComponentsOther
:: [KnownComponent
]
1739 pinfoId
:: PackageId
,
1740 pinfoDirectory
:: Maybe (FilePath, FilePath),
1741 pinfoPackageFile
:: Maybe (FilePath, FilePath),
1742 pinfoComponents
:: [KnownComponent
]
1744 | KnownPackageName
{
1745 pinfoName
:: PackageName
1749 data KnownComponent
= KnownComponent
{
1750 cinfoName
:: ComponentName
,
1751 cinfoStrName
:: ComponentStringName
,
1752 cinfoPackageId
:: PackageId
,
1753 cinfoSrcDirs
:: [FilePath],
1754 cinfoModules
:: [ModuleName
],
1755 cinfoHsFiles
:: [FilePath], -- other hs files (like main.hs)
1756 cinfoCFiles
:: [FilePath],
1757 cinfoJsFiles
:: [FilePath]
1761 type ComponentStringName
= String
1763 knownPackageName
:: KnownPackage
-> PackageName
1764 knownPackageName KnownPackage
{pinfoId
} = packageName pinfoId
1765 knownPackageName KnownPackageName
{pinfoName
} = pinfoName
1767 emptyKnownTargets
:: KnownTargets
1768 emptyKnownTargets
= KnownTargets
[] [] [] [] [] []
1770 getKnownTargets
:: forall m a
. (Applicative m
, Monad m
)
1772 -> [PackageSpecifier
(SourcePackage
(PackageLocation a
))]
1774 getKnownTargets dirActions
@DirActions
{..} pkgs
= do
1775 pinfo
<- traverse
(collectKnownPackageInfo dirActions
) pkgs
1776 cwd
<- getCurrentDirectory
1777 (ppinfo
, opinfo
) <- selectPrimaryPackage cwd pinfo
1778 return KnownTargets
{
1779 knownPackagesAll
= pinfo
,
1780 knownPackagesPrimary
= ppinfo
,
1781 knownPackagesOther
= opinfo
,
1782 knownComponentsAll
= allComponentsIn pinfo
,
1783 knownComponentsPrimary
= allComponentsIn ppinfo
,
1784 knownComponentsOther
= allComponentsIn opinfo
1787 mPkgDir
:: KnownPackage
-> Maybe FilePath
1788 mPkgDir KnownPackage
{ pinfoDirectory
= Just
(dir
,_
) } = Just dir
1791 selectPrimaryPackage
:: FilePath
1793 -> m
([KnownPackage
], [KnownPackage
])
1794 selectPrimaryPackage _
[] = return ([] , [])
1795 selectPrimaryPackage cwd
(pkg
: packages
) = do
1796 (ppinfo
, opinfo
) <- selectPrimaryPackage cwd packages
1797 isPkgDirCwd
<- maybe (pure
False) (compareFilePath dirActions cwd
) (mPkgDir pkg
)
1798 return (if isPkgDirCwd
then (pkg
: ppinfo
, opinfo
) else (ppinfo
, pkg
: opinfo
))
1800 allComponentsIn ps
=
1801 [ c | KnownPackage
{pinfoComponents
} <- ps
, c
<- pinfoComponents
]
1804 collectKnownPackageInfo
:: (Applicative m
, Monad m
) => DirActions m
1805 -> PackageSpecifier
(SourcePackage
(PackageLocation a
))
1807 collectKnownPackageInfo _
(NamedPackage pkgname _props
) =
1808 return (KnownPackageName pkgname
)
1809 collectKnownPackageInfo dirActions
@DirActions
{..}
1810 (SpecificSourcePackage SourcePackage
{
1811 srcpkgDescription
= pkg
,
1814 (pkgdir
, pkgfile
) <-
1816 --TODO: local tarballs, remote tarballs etc
1817 LocalUnpackedPackage dir
-> do
1818 dirabs
<- canonicalizePath dir
1819 dirrel
<- makeRelativeToCwd dirActions dirabs
1820 --TODO: ought to get this earlier in project reading
1821 let fileabs
= dirabs
</> prettyShow
(packageName pkg
) <.> "cabal"
1822 filerel
= dirrel
</> prettyShow
(packageName pkg
) <.> "cabal"
1823 exists
<- doesFileExist fileabs
1824 return ( Just
(dirabs
, dirrel
)
1825 , if exists
then Just
(fileabs
, filerel
) else Nothing
1827 _
-> return (Nothing
, Nothing
)
1830 pinfoId
= packageId pkg
,
1831 pinfoDirectory
= pkgdir
,
1832 pinfoPackageFile
= pkgfile
,
1833 pinfoComponents
= collectKnownComponentInfo
1834 (flattenPackageDescription pkg
)
1839 collectKnownComponentInfo
:: PackageDescription
-> [KnownComponent
]
1840 collectKnownComponentInfo pkg
=
1842 cinfoName
= componentName c
,
1843 cinfoStrName
= componentStringName
(packageName pkg
) (componentName c
),
1844 cinfoPackageId
= packageId pkg
,
1845 cinfoSrcDirs
= ordNub
(map getSymbolicPath
(hsSourceDirs bi
)),
1846 cinfoModules
= ordNub
(componentModules c
),
1847 cinfoHsFiles
= ordNub
(componentHsFiles c
),
1848 cinfoCFiles
= ordNub
(cSources bi
),
1849 cinfoJsFiles
= ordNub
(jsSources bi
)
1851 | c
<- pkgComponents pkg
1852 , let bi
= componentBuildInfo c
]
1855 componentStringName
:: PackageName
-> ComponentName
-> ComponentStringName
1856 componentStringName pkgname
(CLibName LMainLibName
) = prettyShow pkgname
1857 componentStringName _
(CLibName
(LSubLibName name
)) = unUnqualComponentName name
1858 componentStringName _
(CFLibName name
) = unUnqualComponentName name
1859 componentStringName _
(CExeName name
) = unUnqualComponentName name
1860 componentStringName _
(CTestName name
) = unUnqualComponentName name
1861 componentStringName _
(CBenchName name
) = unUnqualComponentName name
1863 componentModules
:: Component
-> [ModuleName
]
1864 -- I think it's unlikely users will ask to build a requirement
1865 -- which is not mentioned locally.
1866 componentModules
(CLib lib
) = explicitLibModules lib
1867 componentModules
(CFLib flib
) = foreignLibModules flib
1868 componentModules
(CExe exe
) = exeModules exe
1869 componentModules
(CTest test
) = testModules test
1870 componentModules
(CBench bench
) = benchmarkModules bench
1872 componentHsFiles
:: Component
-> [FilePath]
1873 componentHsFiles
(CExe exe
) = [modulePath exe
]
1874 componentHsFiles
(CTest TestSuite
{
1875 testInterface
= TestSuiteExeV10 _ mainfile
1877 componentHsFiles
(CBench Benchmark
{
1878 benchmarkInterface
= BenchmarkExeV10 _ mainfile
1880 componentHsFiles _
= []
1883 ------------------------------
1884 -- Matching meta targets
1887 guardNamespaceMeta
:: String -> Match
()
1888 guardNamespaceMeta
= guardToken
[""] "meta namespace"
1890 guardMetaAll
:: String -> Match
()
1891 guardMetaAll
= guardToken
["all"] "meta-target 'all'"
1893 guardNamespacePackage
:: String -> Match
()
1894 guardNamespacePackage
= guardToken
["pkg", "package"] "'pkg' namespace"
1896 guardNamespaceCwd
:: String -> Match
()
1897 guardNamespaceCwd
= guardToken
["cwd"] "'cwd' namespace"
1899 guardNamespaceModule
:: String -> Match
()
1900 guardNamespaceModule
= guardToken
["mod", "module"] "'module' namespace"
1902 guardNamespaceFile
:: String -> Match
()
1903 guardNamespaceFile
= guardToken
["file"] "'file' namespace"
1905 guardToken
:: [String] -> String -> String -> Match
()
1906 guardToken tokens msg s
1907 | caseFold s `
elem` tokens
= increaseConfidence
1908 |
otherwise = matchErrorExpected msg s
1911 ------------------------------
1912 -- Matching component kinds
1915 componentKind
:: ComponentName
-> ComponentKind
1916 componentKind
(CLibName _
) = LibKind
1917 componentKind
(CFLibName _
) = FLibKind
1918 componentKind
(CExeName _
) = ExeKind
1919 componentKind
(CTestName _
) = TestKind
1920 componentKind
(CBenchName _
) = BenchKind
1922 cinfoKind
:: KnownComponent
-> ComponentKind
1923 cinfoKind
= componentKind
. cinfoName
1925 matchComponentKind
:: String -> Match ComponentKind
1926 matchComponentKind s
1927 | s
' `
elem` liblabels
= increaseConfidence
>> return LibKind
1928 | s
' `
elem` fliblabels
= increaseConfidence
>> return FLibKind
1929 | s
' `
elem` exelabels
= increaseConfidence
>> return ExeKind
1930 | s
' `
elem` testlabels
= increaseConfidence
>> return TestKind
1931 | s
' `
elem` benchlabels
= increaseConfidence
>> return BenchKind
1932 |
otherwise = matchErrorExpected
"component kind" s
1935 liblabels
= ["lib", "library"]
1936 fliblabels
= ["flib", "foreign-library"]
1937 exelabels
= ["exe", "executable"]
1938 testlabels
= ["tst", "test", "test-suite"]
1939 benchlabels
= ["bench", "benchmark"]
1941 matchComponentKindFilter
:: String -> Match ComponentKind
1942 matchComponentKindFilter s
1943 | s
' `
elem` liblabels
= increaseConfidence
>> return LibKind
1944 | s
' `
elem` fliblabels
= increaseConfidence
>> return FLibKind
1945 | s
' `
elem` exelabels
= increaseConfidence
>> return ExeKind
1946 | s
' `
elem` testlabels
= increaseConfidence
>> return TestKind
1947 | s
' `
elem` benchlabels
= increaseConfidence
>> return BenchKind
1948 |
otherwise = matchErrorExpected
"component kind filter" s
1951 liblabels
= ["libs", "libraries"]
1952 fliblabels
= ["flibs", "foreign-libraries"]
1953 exelabels
= ["exes", "executables"]
1954 testlabels
= ["tests", "test-suites"]
1955 benchlabels
= ["benches", "benchmarks"]
1957 showComponentKind
:: ComponentKind
-> String
1958 showComponentKind LibKind
= "library"
1959 showComponentKind FLibKind
= "foreign library"
1960 showComponentKind ExeKind
= "executable"
1961 showComponentKind TestKind
= "test-suite"
1962 showComponentKind BenchKind
= "benchmark"
1964 showComponentKindShort
:: ComponentKind
-> String
1965 showComponentKindShort LibKind
= "lib"
1966 showComponentKindShort FLibKind
= "flib"
1967 showComponentKindShort ExeKind
= "exe"
1968 showComponentKindShort TestKind
= "test"
1969 showComponentKindShort BenchKind
= "bench"
1971 showComponentKindFilterShort
:: ComponentKind
-> String
1972 showComponentKindFilterShort LibKind
= "libs"
1973 showComponentKindFilterShort FLibKind
= "flibs"
1974 showComponentKindFilterShort ExeKind
= "exes"
1975 showComponentKindFilterShort TestKind
= "tests"
1976 showComponentKindFilterShort BenchKind
= "benchmarks"
1979 ------------------------------
1980 -- Matching package targets
1983 guardPackage
:: String -> FileStatus
-> Match
()
1984 guardPackage str fstatus
=
1985 guardPackageName str
1986 <|
> guardPackageDir str fstatus
1987 <|
> guardPackageFile str fstatus
1990 guardPackageName
:: String -> Match
()
1992 | validPackageName s
= increaseConfidence
1993 |
otherwise = matchErrorExpected
"package name" s
1995 validPackageName
:: String -> Bool
1996 validPackageName s
=
1997 all validPackageNameChar s
2000 validPackageNameChar c
= isAlphaNum c || c
== '-'
2003 guardPackageDir
:: String -> FileStatus
-> Match
()
2004 guardPackageDir _
(FileStatusExistsDir _
) = increaseConfidence
2005 guardPackageDir str _
= matchErrorExpected
"package directory" str
2008 guardPackageFile
:: String -> FileStatus
-> Match
()
2009 guardPackageFile _
(FileStatusExistsFile file
)
2010 | takeExtension file
== ".cabal"
2011 = increaseConfidence
2012 guardPackageFile str _
= matchErrorExpected
"package .cabal file" str
2015 matchPackage
:: [KnownPackage
] -> String -> FileStatus
-> Match KnownPackage
2016 matchPackage pinfo
= \str fstatus
->
2017 orNoThingIn
"project" "" $
2018 matchPackageName pinfo str
2019 <//> (matchPackageNameUnknown str
2020 <|
> matchPackageDir pinfo str fstatus
2021 <|
> matchPackageFile pinfo str fstatus
)
2024 matchPackageName
:: [KnownPackage
] -> String -> Match KnownPackage
2025 matchPackageName ps
= \str
-> do
2026 guard (validPackageName str
)
2027 orNoSuchThing
"package" str
2028 (map (prettyShow
. knownPackageName
) ps
) $
2029 increaseConfidenceFor
$
2030 matchInexactly caseFold
(prettyShow
. knownPackageName
) ps str
2033 matchPackageNameUnknown
:: String -> Match KnownPackage
2034 matchPackageNameUnknown str
= do
2035 pn
<- matchParse str
2036 unknownMatch
(KnownPackageName pn
)
2039 matchPackageDir
:: [KnownPackage
]
2040 -> String -> FileStatus
-> Match KnownPackage
2041 matchPackageDir ps
= \str fstatus
->
2043 FileStatusExistsDir canondir
->
2044 orNoSuchThing
"package directory" str
(map (snd . fst) dirs
) $
2045 increaseConfidenceFor
$
2046 fmap snd $ matchExactly
(fst . fst) dirs canondir
2049 dirs
= [ ((dabs
,drel
),p
)
2050 | p
@KnownPackage
{ pinfoDirectory
= Just
(dabs
,drel
) } <- ps
]
2053 matchPackageFile
:: [KnownPackage
] -> String -> FileStatus
-> Match KnownPackage
2054 matchPackageFile ps
= \str fstatus
-> do
2056 FileStatusExistsFile canonfile
->
2057 orNoSuchThing
"package .cabal file" str
(map (snd . fst) files
) $
2058 increaseConfidenceFor
$
2059 fmap snd $ matchExactly
(fst . fst) files canonfile
2062 files
= [ ((fabs
,frel
),p
)
2063 | p
@KnownPackage
{ pinfoPackageFile
= Just
(fabs
,frel
) } <- ps
]
2065 --TODO: test outcome when dir exists but doesn't match any known one
2067 --TODO: perhaps need another distinction, vs no such thing, point is the
2068 -- thing is not known, within the project, but could be outside project
2071 ------------------------------
2072 -- Matching component targets
2076 guardComponentName
:: String -> Match
()
2077 guardComponentName s
2078 |
all validComponentChar s
2079 && not (null s
) = increaseConfidence
2080 |
otherwise = matchErrorExpected
"component name" s
2082 validComponentChar c
= isAlphaNum c || c
== '.'
2083 || c
== '_
' || c
== '-' || c
== '\''
2086 matchComponentName
:: [KnownComponent
] -> String -> Match KnownComponent
2087 matchComponentName cs str
=
2088 orNoSuchThing
"component" str
(map cinfoStrName cs
)
2089 $ increaseConfidenceFor
2090 $ matchInexactly caseFold cinfoStrName cs str
2093 matchComponentKindAndName
:: [KnownComponent
] -> ComponentKind
-> String
2094 -> Match KnownComponent
2095 matchComponentKindAndName cs ckind str
=
2096 orNoSuchThing
(showComponentKind ckind
++ " component") str
2098 $ increaseConfidenceFor
2099 $ matchInexactly
(\(ck
, cn
) -> (ck
, caseFold cn
))
2100 (\c
-> (cinfoKind c
, cinfoStrName c
))
2104 render c
= showComponentKindShort
(cinfoKind c
) ++ ":" ++ cinfoStrName c
2107 ------------------------------
2108 -- Matching module targets
2111 guardModuleName
:: String -> Match
()
2113 case simpleParsec s
:: Maybe ModuleName
of
2114 Just _
-> increaseConfidence
2115 _ |
all validModuleChar s
2116 && not (null s
) -> return ()
2117 |
otherwise -> matchErrorExpected
"module name" s
2119 validModuleChar c
= isAlphaNum c || c
== '.' || c
== '_
' || c
== '\''
2122 matchModuleName
:: [ModuleName
] -> String -> Match ModuleName
2123 matchModuleName ms str
=
2124 orNoSuchThing
"module" str
(map prettyShow ms
)
2125 $ increaseConfidenceFor
2126 $ matchInexactly caseFold prettyShow ms str
2129 matchModuleNameAnd
:: [(ModuleName
, a
)] -> String -> Match
(ModuleName
, a
)
2130 matchModuleNameAnd ms str
=
2131 orNoSuchThing
"module" str
(map (prettyShow
. fst) ms
)
2132 $ increaseConfidenceFor
2133 $ matchInexactly caseFold
(prettyShow
. fst) ms str
2136 matchModuleNameUnknown
:: String -> Match ModuleName
2137 matchModuleNameUnknown str
=
2138 expecting
"module" str
2139 $ increaseConfidenceFor
2143 ------------------------------
2144 -- Matching file targets
2147 matchPackageDirectoryPrefix
:: [KnownPackage
] -> FileStatus
2148 -> Match
(FilePath, KnownPackage
)
2149 matchPackageDirectoryPrefix ps
(FileStatusExistsFile filepath
) =
2150 increaseConfidenceFor
$
2151 matchDirectoryPrefix pkgdirs filepath
2153 pkgdirs
= [ (dir
, p
)
2154 | p
@KnownPackage
{ pinfoDirectory
= Just
(dir
,_
) } <- ps
]
2155 matchPackageDirectoryPrefix _ _
= mzero
2158 matchComponentFile
:: [KnownComponent
] -> String
2159 -> Match
(FilePath, KnownComponent
)
2160 matchComponentFile cs str
=
2161 orNoSuchThing
"file" str
[] $
2162 matchComponentModuleFile cs str
2163 <|
> matchComponentOtherFile cs str
2166 matchComponentOtherFile
:: [KnownComponent
] -> String
2167 -> Match
(FilePath, KnownComponent
)
2168 matchComponentOtherFile cs
=
2170 [ (normalise
(srcdir
</> file
), c
)
2172 , srcdir
<- cinfoSrcDirs c
2173 , file
<- cinfoHsFiles c
2180 matchComponentModuleFile
:: [KnownComponent
] -> String
2181 -> Match
(FilePath, KnownComponent
)
2182 matchComponentModuleFile cs str
= do
2184 [ (normalise
(d
</> toFilePath m
), c
)
2186 , d
<- cinfoSrcDirs c
2187 , m
<- cinfoModules c
2189 (dropExtension
(normalise str
)) -- Drop the extension because FileTarget
2190 -- is stored without the extension
2194 -- | Compare two filepaths for equality using DirActions' canonicalizePath
2195 -- to normalize AND canonicalize filepaths before comparison.
2196 compareFilePath
:: (Applicative m
, Monad m
) => DirActions m
2197 -> FilePath -> FilePath -> m
Bool
2198 compareFilePath DirActions
{..} fp1 fp2
2199 | equalFilePath fp1 fp2
= pure
True -- avoid unnecessary IO if we can match earlier
2201 c1
<- canonicalizePath fp1
2202 c2
<- canonicalizePath fp2
2203 pure
$ equalFilePath c1 c2
2206 matchFile
:: [(FilePath, a
)] -> FilePath -> Match
(FilePath, a
)
2208 increaseConfidenceFor
2209 . matchInexactly caseFold
fst fs
2211 matchDirectoryPrefix
:: [(FilePath, a
)] -> FilePath -> Match
(FilePath, a
)
2212 matchDirectoryPrefix dirs filepath
=
2216 , file
<- maybeToList (stripDirectory dir
) ]
2218 stripDirectory
:: FilePath -> Maybe FilePath
2219 stripDirectory dir
=
2220 joinPath `
fmap` stripPrefix
(splitDirectories dir
) filepathsplit
2222 filepathsplit
= splitDirectories filepath
2225 ------------------------------
2229 -- | A matcher embodies a way to match some input as being some recognised
2230 -- value. In particular it deals with multiple and ambiguous matches.
2232 -- There are various matcher primitives ('matchExactly', 'matchInexactly'),
2233 -- ways to combine matchers ('matchPlus', 'matchPlusShadowing') and finally we
2234 -- can run a matcher against an input using 'findMatch'.
2236 data Match a
= NoMatch
!Confidence
[MatchError
]
2237 | Match
!MatchClass
!Confidence
[a
]
2240 -- | The kind of match, inexact or exact. We keep track of this so we can
2241 -- prefer exact over inexact matches. The 'Ord' here is important: we try
2242 -- to maximise this, so 'Exact' is the top value and 'Inexact' the bottom.
2244 data MatchClass
= Unknown
-- ^ Matches an unknown thing e.g. parses as a package
2245 -- name without it being a specific known package
2246 | Inexact
-- ^ Matches a known thing inexactly
2247 -- e.g. matches a known package case insensitively
2248 | Exact
-- ^ Exactly matches a known thing,
2249 -- e.g. matches a known package case sensitively
2250 deriving (Show, Eq
, Ord
)
2252 type Confidence
= Int
2254 data MatchError
= MatchErrorExpected
String String -- thing got
2255 | MatchErrorNoSuch
String String [String] -- thing got alts
2256 | MatchErrorIn
String String MatchError
-- kind thing
2260 instance Functor Match
where
2261 fmap _
(NoMatch d ms
) = NoMatch d ms
2262 fmap f
(Match m d xs
) = Match m d
(fmap f xs
)
2264 instance Applicative Match
where
2265 pure a
= Match Exact
0 [a
]
2268 instance Alternative Match
where
2269 empty = NoMatch
0 []
2272 instance Monad Match
where
2274 NoMatch d ms
>>= _
= NoMatch d ms
2275 Match m d xs
>>= f
=
2276 -- To understand this, it needs to be read in context with the
2277 -- implementation of 'matchPlus' below
2278 case msum (map f xs
) of
2279 Match m
' d
' xs
' -> Match
(min m m
') (d
+ d
') xs
'
2280 -- The minimum match class is the one we keep. The match depth is
2281 -- tracked but not used in the Match case.
2283 NoMatch d
' ms
-> NoMatch
(d
+ d
') ms
2284 -- Here is where we transfer the depth we were keeping track of in
2285 -- the Match case over to the NoMatch case where it finally gets used.
2287 instance MonadPlus Match
where
2291 (<//>) :: Match a
-> Match a
-> Match a
2292 (<//>) = matchPlusShadowing
2296 -- | Combine two matchers. Exact matches are used over inexact matches
2297 -- but if we have multiple exact, or inexact then the we collect all the
2298 -- ambiguous matches.
2300 -- This operator is associative, has unit 'mzero' and is also commutative.
2302 matchPlus
:: Match a
-> Match a
-> Match a
2303 matchPlus a
@(Match _ _ _
) (NoMatch _ _
) = a
2304 matchPlus
(NoMatch _ _
) b
@(Match _ _ _
) = b
2305 matchPlus a
@(NoMatch d_a ms_a
) b
@(NoMatch d_b ms_b
)
2306 | d_a
> d_b
= a
-- We only really make use of the depth in the NoMatch case.
2308 |
otherwise = NoMatch d_a
(ms_a
++ ms_b
)
2309 matchPlus a
@(Match m_a d_a xs_a
) b
@(Match m_b d_b xs_b
)
2310 | m_a
> m_b
= a
-- exact over inexact
2311 | m_a
< m_b
= b
-- exact over inexact
2312 |
otherwise = Match m_a
(max d_a d_b
) (xs_a
++ xs_b
)
2314 -- | Combine two matchers. This is similar to 'matchPlus' with the
2315 -- difference that an exact match from the left matcher shadows any exact
2316 -- match on the right. Inexact matches are still collected however.
2318 -- This operator is associative, has unit 'mzero' and is not commutative.
2320 matchPlusShadowing
:: Match a
-> Match a
-> Match a
2321 matchPlusShadowing a
@(Match Exact _ _
) _
= a
2322 matchPlusShadowing a b
= matchPlus a b
2325 ------------------------------
2326 -- Various match primitives
2329 matchErrorExpected
:: String -> String -> Match a
2330 matchErrorExpected thing got
= NoMatch
0 [MatchErrorExpected thing got
]
2332 matchErrorNoSuch
:: String -> String -> [String] -> Match a
2333 matchErrorNoSuch thing got alts
= NoMatch
0 [MatchErrorNoSuch thing got alts
]
2335 expecting
:: String -> String -> Match a
-> Match a
2336 expecting thing got
(NoMatch
0 _
) = matchErrorExpected thing got
2339 orNoSuchThing
:: String -> String -> [String] -> Match a
-> Match a
2340 orNoSuchThing thing got alts
(NoMatch
0 _
) = matchErrorNoSuch thing got alts
2341 orNoSuchThing _ _ _ m
= m
2343 orNoThingIn
:: String -> String -> Match a
-> Match a
2344 orNoThingIn kind name
(NoMatch n ms
) =
2345 NoMatch n
[ MatchErrorIn kind name m | m
<- ms
]
2346 orNoThingIn _ _ m
= m
2348 increaseConfidence
:: Match
()
2349 increaseConfidence
= Match Exact
1 [()]
2351 increaseConfidenceFor
:: Match a
-> Match a
2352 increaseConfidenceFor m
= m
>>= \r -> increaseConfidence
>> return r
2354 nubMatchesBy
:: (a
-> a
-> Bool) -> Match a
-> Match a
2355 nubMatchesBy _
(NoMatch d msgs
) = NoMatch d msgs
2356 nubMatchesBy eq
(Match m d xs
) = Match m d
(nubBy eq xs
)
2358 -- | Lift a list of matches to an exact match.
2360 exactMatches
, inexactMatches
:: [a
] -> Match a
2362 exactMatches
[] = mzero
2363 exactMatches xs
= Match Exact
0 xs
2365 inexactMatches
[] = mzero
2366 inexactMatches xs
= Match Inexact
0 xs
2368 unknownMatch
:: a
-> Match a
2369 unknownMatch x
= Match Unknown
0 [x
]
2371 tryEach
:: [a
] -> Match a
2372 tryEach
= exactMatches
2375 ------------------------------
2376 -- Top level match runner
2379 -- | Given a matcher and a key to look up, use the matcher to find all the
2380 -- possible matches. There may be 'None', a single 'Unambiguous' match or
2381 -- you may have an 'Ambiguous' match with several possibilities.
2383 findMatch
:: Match a
-> MaybeAmbiguous a
2384 findMatch match
= case match
of
2385 NoMatch _ msgs
-> None msgs
2386 Match _ _
[x
] -> Unambiguous x
2387 Match m d
[] -> error $ "findMatch: impossible: " ++ show match
'
2388 where match
' = Match m d
[] :: Match
()
2389 -- TODO: Maybe use Data.List.NonEmpty inside
2390 -- Match so that this case would be correct
2392 Match m _ xs
-> Ambiguous m xs
2394 data MaybeAmbiguous a
= None
[MatchError
]
2396 | Ambiguous MatchClass
[a
]
2400 ------------------------------
2404 -- | A primitive matcher that looks up a value in a finite 'Map'. The
2405 -- value must match exactly.
2407 matchExactly
:: Ord k
=> (a
-> k
) -> [a
] -> (k
-> Match a
)
2408 matchExactly key xs
=
2409 \k
-> case Map
.lookup k m
of
2411 Just ys
-> exactMatches ys
2413 m
= Map
.fromListWith
(++) [ (key x
, [x
]) | x
<- xs
]
2415 -- | A primitive matcher that looks up a value in a finite 'Map'. It checks
2416 -- for an exact or inexact match. We get an inexact match if the match
2417 -- is not exact, but the canonical forms match. It takes a canonicalisation
2418 -- function for this purpose.
2420 -- So for example if we used string case fold as the canonicalisation
2421 -- function, then we would get case insensitive matching (but it will still
2422 -- report an exact match when the case matches too).
2424 matchInexactly
:: (Ord k
, Ord k
') => (k
-> k
') -> (a
-> k
)
2425 -> [a
] -> (k
-> Match a
)
2426 matchInexactly cannonicalise key xs
=
2427 \k
-> case Map
.lookup k m
of
2428 Just ys
-> exactMatches ys
2429 Nothing
-> case Map
.lookup (cannonicalise k
) m
' of
2430 Just ys
-> inexactMatches ys
2433 m
= Map
.fromListWith
(++) [ (key x
, [x
]) | x
<- xs
]
2435 -- the map of canonicalised keys to groups of inexact matches
2436 m
' = Map
.mapKeysWith
(++) cannonicalise m
2438 matchParse
:: Parsec a
=> String -> Match a
2439 matchParse
= maybe mzero
return . simpleParsec
2442 ------------------------------
2446 caseFold
:: String -> String
2447 caseFold
= lowercase
2449 -- | Make a 'ComponentName' given an 'UnqualComponentName' and knowing the
2450 -- 'ComponentKind'. We also need the 'PackageName' to distinguish the package's
2451 -- primary library from named private libraries.
2453 mkComponentName
:: PackageName
2455 -> UnqualComponentName
2457 mkComponentName pkgname ckind ucname
=
2460 | packageNameToUnqualComponentName pkgname
== ucname
2461 -> CLibName LMainLibName
2462 |
otherwise -> CLibName
$ LSubLibName ucname
2463 FLibKind
-> CFLibName ucname
2464 ExeKind
-> CExeName ucname
2465 TestKind
-> CTestName ucname
2466 BenchKind
-> CBenchName ucname
2469 ------------------------------
2474 ex1pinfo :: [KnownPackage]
2476 [ addComponent (CExeName (mkUnqualComponentName "foo-exe")) [] ["Data.Foo"] $
2478 pinfoId = PackageIdentifier (mkPackageName "foo") (mkVersion [1]),
2479 pinfoDirectory = Just ("/the/foo", "foo"),
2480 pinfoPackageFile = Just ("/the/foo/foo.cabal", "foo/foo.cabal"),
2481 pinfoComponents = []
2484 pinfoId = PackageIdentifier (mkPackageName "bar") (mkVersion [1]),
2485 pinfoDirectory = Just ("/the/bar", "bar"),
2486 pinfoPackageFile = Just ("/the/bar/bar.cabal", "bar/bar.cabal"),
2487 pinfoComponents = []
2491 addComponent n ds ms p =
2494 KnownComponent n (componentStringName (pinfoId p) n)
2500 mkMn :: String -> ModuleName
2501 mkMn = ModuleName.fromString
2505 [ TargetComponent (CExeName "foo") WholeComponent
2506 , TargetComponent (CExeName "foo") (ModuleTarget (mkMn "Foo"))
2507 , TargetComponent (CExeName "tst") (ModuleTarget (mkMn "Foo"))
2510 mkMn :: String -> ModuleName
2511 mkMn = fromJust . simpleParse
2513 ex_pkgid :: PackageIdentifier
2514 Just ex_pkgid = simpleParse "thelib"
2518 ex_cs :: [KnownComponent]
2520 [ (mkC (CExeName "foo") ["src1", "src1/src2"] ["Foo", "Src2.Bar", "Bar"])
2521 , (mkC (CExeName "tst") ["src1", "test"] ["Foo"])
2524 mkC n ds ms = KnownComponent n (componentStringName n) ds (map mkMn ms)
2525 mkMn :: String -> ModuleName
2526 mkMn = fromJust . simpleParse
2527 pkgid :: PackageIdentifier
2528 Just pkgid = simpleParse "thelib"