| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
PbtCli.Discover
Description
Static, no-compile discovery of a Haskell repository's cabal projects, packages and test suites.
This is a native port of scripts/list-test-suites/list-test-suites.sh. It
emits the same JSON document, validating against that tool's
list-test-suites.schema.json, so anything already consuming the script's
output can consume pbt-cli suites --json unchanged. The port exists because
the shipped pbt-cli binary must work on its own: a downloaded binary has no
repository checkout to find a bash script in.
Nothing here compiles or even configures anything — it reads *.cabal and
cabal.project* as text, which is why it takes milliseconds.
The one deliberate divergence from the shell implementation: a trailing comma
on a packages: entry is stripped, because cabal itself accepts
comma-separated lists and the shell version would silently drop such a package.
Synopsis
- data Discovery = Discovery {
- discRoot :: FilePath
- discProjects :: [Project]
- discOrphans :: [Orphan]
- data Project = Project {}
- data Package = Package {}
- data TestSuite = TestSuite {}
- data Orphan = Orphan {}
- data EntryPoint
- entryPointText :: EntryPoint -> Text
- discover :: FilePath -> IO Discovery
- isCompatible :: TestSuite -> Bool
- compatibleOnly :: Discovery -> Discovery
- data SuiteRef = SuiteRef {}
- flattenSuites :: Discovery -> [SuiteRef]
- findSuite :: Text -> Discovery -> Maybe SuiteRef
- entryPointOfFile :: FilePath -> IO EntryPoint
- classifySource :: String -> EntryPoint
- parseTestSuites :: FilePath -> FilePath -> String -> IO [TestSuite]
- packageNameOf :: String -> Text
- projectFilesIn :: FilePath -> IO [FilePath]
- findCabalFiles :: FilePath -> IO [FilePath]
- readFileLenient :: FilePath -> IO String
Types
The whole discovery result.
Constructors
| Discovery | |
Fields
| |
One cabal.project* file, or the implicit project when there is none.
Constructors
| Project | |
Fields
| |
A package, rendered under exactly one project (see primaryOwner).
Constructors
| Package | |
Fields
| |
A single test-suite stanza, with the commands that drive it.
Constructors
| TestSuite | |
Fields
| |
A .cabal file no project's packages: field reaches.
Constructors
| Orphan | |
Fields | |
data EntryPoint Source #
How a test suite's main-is module runs its tests.
Only Streaming suites provide the --streaming-json and --list-tests-json
ingredients, because those come from the convex-tasty-streaming library. That
makes Streaming the operational definition of "sc-testing-tools compatible".
Constructors
| Streaming |
|
| Upstream | plain |
| UnknownEntry | a |
| MissingEntry | the |
Instances
| ToJSON EntryPoint Source # | |
Defined in PbtCli.Discover Methods toJSON :: EntryPoint -> Value Source # toEncoding :: EntryPoint -> Encoding Source # toJSONList :: [EntryPoint] -> Value Source # toEncodingList :: [EntryPoint] -> Encoding Source # omitField :: EntryPoint -> Bool Source # | |
| Show EntryPoint Source # | |
Defined in PbtCli.Discover Methods showsPrec :: Int -> EntryPoint -> ShowS # show :: EntryPoint -> String # showList :: [EntryPoint] -> ShowS # | |
| Eq EntryPoint Source # | |
Defined in PbtCli.Discover | |
| Ord EntryPoint Source # | |
Defined in PbtCli.Discover Methods compare :: EntryPoint -> EntryPoint -> Ordering # (<) :: EntryPoint -> EntryPoint -> Bool # (<=) :: EntryPoint -> EntryPoint -> Bool # (>) :: EntryPoint -> EntryPoint -> Bool # (>=) :: EntryPoint -> EntryPoint -> Bool # max :: EntryPoint -> EntryPoint -> EntryPoint # min :: EntryPoint -> EntryPoint -> EntryPoint # | |
entryPointText :: EntryPoint -> Text Source #
The wire name, as it appears in the JSON and in --tsv output.
Discovery
discover :: FilePath -> IO Discovery Source #
Scan root and report every project, package and test suite.
Warnings (orphan .cabal files, packages claimed by several non-default
projects) go to stderr, matching the shell tool, so stdout stays a single
parseable JSON document.
Compatibility
isCompatible :: TestSuite -> Bool Source #
Is this suite sc-testing-tools compatible — that is, does it support
--list-tests-json, --streaming-json and the threat-model options?
compatibleOnly :: Discovery -> Discovery Source #
Drop every non-Streaming suite, and then every package and project left
without suites. Used by --compatible-only.
Flattened views
A suite together with the context needed to actually run it: which project file owns it and which package it lives in.
The JSON document is intentionally nested (and its schema forbids extra
fields), so this flattened view is what the run stream tests
commands work with.
flattenSuites :: Discovery -> [SuiteRef] Source #
Every suite in the discovery, in document order, paired with its project file and package.
srProjectFile is Nothing both for the implicit project and for the default
cabal.project, because in either case cabal needs no --project-file flag.
findSuite :: Text -> Discovery -> Maybe SuiteRef Source #
Look a suite up by its cabal test target name.
Reusable pieces
entryPointOfFile :: FilePath -> IO EntryPoint Source #
Classify a main-is source file by the tasty runner it calls.
Streaming is tested first so the *WithIngredients variants are never
mistaken for plain upstream defaultMain.
classifySource :: String -> EntryPoint Source #
The pure half of entryPointOfFile.
Arguments
| :: FilePath | absolute root |
| -> FilePath | package dir, relative to root |
| -> String | the |
| -> IO [TestSuite] |
Parse the test-suite stanzas of one .cabal file.
A stanza runs from a test-suite <name> line at column 0 until the next
column-0 declaration. main-is is resolved against each of the stanza's
hs-source-dirs in order; the first path that exists on disk wins and its
source is classified. When none exists the suite is reported as MISSING,
which keeps a typo'd (or generated-but-absent) entry point visible instead of
silently dropping the suite.
packageNameOf :: String -> Text Source #
The package's name: field, or "" when it has none.
projectFilesIn :: FilePath -> IO [FilePath] Source #
The cabal.project / cabal.project.* files at the top level of root,
sorted.
Only the top level is scanned because that is the only place cabal honours
them, and .freeze / .local are excluded: they configure a project rather
than declaring one.
findCabalFiles :: FilePath -> IO [FilePath] Source #
Every .cabal file under root, relative to it and sorted.
dist-newstyle, tasty-investigate, .git and node_modules are pruned:
they hold build artefacts and vendored code whose .cabal files are not part
of the repository's own structure. Symlinks are not followed at all -- neither
descended into nor reported as .cabal files -- which is what the reference's
find does and what keeps a link back to an ancestor from looping.
readFileLenient :: FilePath -> IO String Source #
Read a file without letting a stray non-UTF-8 byte abort discovery.
Vendored .cabal files and generated sources sometimes carry latin-1 bytes.
The classifier only looks for ASCII markers, so transliterating one byte is
harmless, whereas a decoding exception would lose the entire scan.