convex-pbt-cli
Safe HaskellSafe-Inferred
LanguageHaskell2010

PbtCli.Cabal

Description

Constructing and running the cabal test invocations that back every pbt-cli command.

Two details here are load-bearing.

First, custom test options are passed with repeated singular --test-option= flags, never the plural --test-options=. Cabal splits the plural form on whitespace, so a Tasty pattern containing a space — which is the common case, since Tasty group names have spaces — would arrive at the test binary as several mangled arguments. The singular form appends one argument verbatim.

Second, nothing here goes through a shell. Arguments are handed to the process as a list, so patterns, redeemer names and paths need no quoting and cannot be re-interpreted. renderCommand exists only to *show* a copy-pasteable equivalent for --dry-run and error messages.

Synopsis

Invocations

data Invocation Source #

A resolved cabal command line, ready to run.

Constructors

Invocation 

Fields

Instances

Instances details
Show Invocation Source # 
Instance details

Defined in PbtCli.Cabal

Eq Invocation Source # 
Instance details

Defined in PbtCli.Cabal

testInvocation Source #

Arguments

:: FilePath

cabal executable

-> FilePath

working directory (the repository root)

-> Maybe FilePath

--project-file, when the suites are not in the default project

-> [String]

cabal test targets

-> TestOptions 
-> Invocation 

Build a cabal test invocation.

targets are suite names; passing several is what lets pbt-cli run launch a whole project's suites in one cabal call. An empty target list means all, cabal's own everything-target.

For the structured modes this forces --test-show-details=direct. Cabal's default streams the suite's stdout through, but a target repository is free to set test-show-details: failures or never in its cabal.project (or cabal.project.local, or ~/.cabal/config), and then cabal captures that stdout into a log under dist-newstyle and our pipe receives nothing at all -- so run --json would exit 0 having emitted no events. pbt-cli owns the pipe, so it owns the setting; a later flag on the command line wins over the project file, which makes this a safe unconditional override.

direct rather than streaming: both forward the suite's stdout, but streaming adds cabal's own per-test decoration, and the NDJSON modes want the suite's bytes and nothing else. Plain run is left alone -- it is a pass-through of cabal's console output, so the project's own preference is the right one there.

renderCommand :: Invocation -> String Source #

A copy-pasteable shell rendering of an invocation.

For display only — the real invocation never touches a shell. Arguments are single-quoted when they contain anything that a shell would treat specially.

Test options

data TestOptions Source #

The custom test options pbt-cli knows how to forward to a suite.

Constructors

TestOptions 

Fields

Instances

Instances details
Show TestOptions Source # 
Instance details

Defined in PbtCli.Cabal

Eq TestOptions Source # 
Instance details

Defined in PbtCli.Cabal

noTestOptions :: TestOptions Source #

No custom options: run the suite exactly as cabal test would.

testOptionArgs :: TestOptions -> [String] Source #

Render test options as --test-option= flags.

Flags that take a value contribute two arguments (--test-option=-p then --test-option=<value>) because that is how Tasty's own parser reads them, and it keeps values with spaces intact.

wantsStructuredOutput :: TestOptions -> Bool Source #

Does this invocation need the suite's stdout on our pipe?

True for every mode that parses NDJSON off it. Used to decide whether to override the project's test-show-details.

Running

runInherit :: Invocation -> IO ExitCode Source #

Run an invocation with the child's stdio connected straight to ours.

Used by pbt-cli run so cabal's build progress and Tasty's console reporter appear exactly as they would if the user had typed the cabal command.

runCapture :: Invocation -> IO (ExitCode, [ByteString]) Source #

Run an invocation, collecting its stdout lines and letting stderr through.

stderr stays connected to ours on purpose: cabal reports build failures there, and swallowing them would turn a compile error into a mystifying "no events" result.

runStreaming :: Invocation -> (ByteString -> IO ()) -> IO ExitCode Source #

Run an invocation, handing each stdout line to a callback as it arrives.

The child's stdout is line-buffered and consumed incrementally, which is what makes pbt-cli stream actually live rather than a delayed dump at exit.

Environment

findCabal :: IO FilePath Source #

Locate cabal, or fail with an actionable message.

newtype CabalMissing Source #

Thrown when cabal is not on PATH; pbt-cli is a wrapper, not a build system, so it cannot do anything useful without it.

Constructors

CabalMissing String