hinagata-cli-0.1.0.0: src/Hinagata/Cli/Options.hs
module Hinagata.Cli.Options
( CliOptions (..),
Command (..),
Shell (..),
parserInfo,
)
where
import Control.Applicative (many, optional, some)
import Data.Text qualified as Text
import Options.Applicative (Parser, ParserInfo)
import Options.Applicative qualified as Options
import Settei.Optparse qualified as SetteiOptions
data Shell = Bash | Zsh | Fish
deriving stock (Eq, Show)
data Command
= FixturePlan ![Text.Text] !Bool
| FixtureLoad ![Text.Text] !Text.Text !Bool
| FixtureValidate ![Text.Text] !Bool !Bool
| DbPrepare !Bool
| DbAcquire ![Text.Text] !Bool
| DbWith ![Text.Text] !Bool !Bool ![String]
| DbRelease !Text.Text !Bool
| Inspect !Text.Text !Bool
| Clean !Bool !Bool ![Text.Text] !Bool
| Completions !Shell
deriving stock (Eq, Show)
data CliOptions = CliOptions
{ configPaths :: ![FilePath],
overrides :: ![SetteiOptions.CliOverride],
diagnosticMode :: !SetteiOptions.DiagnosticMode,
command :: !(Maybe Command)
}
parserInfo :: String -> ParserInfo CliOptions
parserInfo version =
Options.info
(cliOptionsParser Options.<**> Options.helper Options.<**> Options.infoOption version (Options.long "version" <> Options.help "Show package version and build revision"))
(Options.fullDesc <> Options.progDesc "Plan fixtures and manage isolated PostgreSQL test databases" <> Options.failureCode 2)
cliOptionsParser :: Parser CliOptions
cliOptionsParser =
CliOptions
<$> Options.parserOptionGroup "Configuration" SetteiOptions.configPathOptions
<*> Options.parserOptionGroup "Configuration" SetteiOptions.overrideOptions
<*> Options.parserOptionGroup "Diagnostics" SetteiOptions.diagnosticModeOptions
<*> optional commandParser
commandParser :: Parser Command
commandParser =
Options.hsubparser
( Options.command "fixture" (Options.info fixtureParser (Options.progDesc "Plan or load fixture sources"))
<> Options.command "db" (Options.info dbParser (Options.progDesc "Manage isolated database leases"))
<> Options.command "inspect" (Options.info inspectParser (Options.progDesc "Inspect a lease by ID"))
<> Options.command "clean" (Options.info cleanParser (Options.progDesc "Preview or apply ownership-checked cleanup"))
<> Options.command "completions" (Options.info completionParser (Options.progDesc "Print a shell completion script"))
)
fixtureParser :: Parser Command
fixtureParser =
Options.hsubparser
( Options.command "plan" (Options.info planParser (Options.progDesc "Compile and inspect a fixture plan without PostgreSQL"))
<> Options.command "load" (Options.info loadParser (Options.progDesc "Transactionally load fixtures into an existing test database"))
<> Options.command "validate" (Options.info validateParser (Options.progDesc "Test each scenario in a separate isolated clone"))
)
planParser :: Parser Command
planParser =
FixturePlan
<$> (fmap Text.pack <$> some (Options.strArgument (Options.metavar "NAME...")))
<*> Options.switch (Options.long "json" <> Options.help "Print versioned JSON")
loadParser :: Parser Command
loadParser =
FixtureLoad
<$> (fmap Text.pack <$> some (Options.strArgument (Options.metavar "NAME...")))
<*> (Text.pack <$> Options.strOption (Options.long "target-database" <> Options.metavar "DATABASE" <> Options.help "Existing caller-owned test database to write"))
<*> Options.switch (Options.long "json" <> Options.help "Print versioned JSON")
validateParser :: Parser Command
validateParser =
FixtureValidate
<$> many (Text.pack <$> Options.strArgument (Options.metavar "NAME..."))
<*> Options.switch (Options.long "all" <> Options.help "Discover all fixture sources")
<*> jsonSwitch
dbParser :: Parser Command
dbParser =
Options.hsubparser
( Options.command "prepare" (Options.info (DbPrepare <$> jsonSwitch) (Options.progDesc "Build or reuse a sealed baseline"))
<> Options.command "acquire" (Options.info acquireParser (Options.progDesc "Acquire a detached isolated database"))
<> Options.command "with" (Options.info withParser (Options.progDesc "Run one command with an isolated database lease"))
<> Options.command "release" (Options.info releaseParser (Options.progDesc "Release a detached or retained lease"))
)
acquireParser :: Parser Command
acquireParser =
DbAcquire
<$> many (Text.pack <$> Options.strOption (Options.long "fixture" <> Options.metavar "NAME" <> Options.help "Scenario fixture (repeatable)"))
<*> jsonSwitch
withParser :: Parser Command
withParser =
DbWith
<$> many (Text.pack <$> Options.strOption (Options.long "fixture" <> Options.metavar "NAME" <> Options.help "Scenario fixture (repeatable)"))
<*> Options.switch (Options.long "preserve-on-failure" <> Options.help "Retain a failed command's database for inspection")
<*> jsonSwitch
<*> some (Options.strArgument (Options.metavar "-- PROGRAM ARGS..."))
jsonSwitch :: Parser Bool
jsonSwitch = Options.switch (Options.long "json" <> Options.help "Print versioned JSON")
releaseParser :: Parser Command
releaseParser =
DbRelease
<$> (Text.pack <$> Options.strArgument (Options.metavar "LEASE_ID"))
<*> Options.switch (Options.long "json" <> Options.help "Print versioned JSON")
inspectParser :: Parser Command
inspectParser =
Inspect
<$> (Text.pack <$> Options.strArgument (Options.metavar "LEASE_ID"))
<*> Options.switch (Options.long "json" <> Options.help "Print versioned JSON")
cleanParser :: Parser Command
cleanParser =
Clean
<$> Options.switch (Options.long "apply" <> Options.help "Revalidate and apply cleanup to selected allocations")
<*> Options.switch (Options.long "include-retained" <> Options.help "Allow explicitly selected retained allocations")
<*> many (Text.pack <$> Options.strOption (Options.long "id" <> Options.metavar "ALLOCATION_ID" <> Options.help "Allocation to revalidate and clean"))
<*> Options.switch (Options.long "json" <> Options.help "Print versioned JSON")
completionParser :: Parser Command
completionParser = Completions <$> Options.argument shellReader (Options.metavar "bash|zsh|fish")
shellReader :: Options.ReadM Shell
shellReader = Options.eitherReader $ \case
"bash" -> Right Bash
"zsh" -> Right Zsh
"fish" -> Right Fish
_ -> Left "expected bash, zsh, or fish"