Safe Haskell | None |
---|---|
Language | Haskell2010 |
Invoking a command-line program (be it tool or daemon) consists of listing the name of its binary, optionally supplying various options to adjust the behaviour of the program, and then supplying mandatory arguments, if any are specified.
On startup, we parse any arguments passed in from the shell into
name,value
pairs and incorporated into the resultant configuration stored
in the program's Context.
Additionally, this module allows you to specify environment variables that, if present, will be incorporated into the stored configuration.
Synopsis
- data Config
- blank :: Config
- simple :: [Options] -> Config
- complex :: [Commands] -> Config
- data Parameters = Parameters {}
- data ParameterValue
- newtype LongName = LongName String
- type ShortName = Char
- type Description = Rope
- data Options
- data Commands
- parseCommandLine :: Config -> [String] -> Either InvalidCommandLine Parameters
- data InvalidCommandLine
Setup
A completely empty configuration, without the default debugging and logging
options. Your program won't process any command-line options or arguments,
which would be weird in most cases. Prefer simple
.
simple :: [Options] -> Config Source #
Declare a simple (as in normal) configuration for a program with any number of optional parameters and mandatory arguments. For example:
main ::IO
() main = do context <-configure
"1.0"None
(simple
[Option
"host" (Just
'h')Empty
[quote
| Specify an alternate host to connect to when performing the frobnication. The default is "localhost". |] ,Option
"port" (Just
'p')Empty
[quote
| Specify an alternate port to connect to when frobnicating. |] ,Option
"dry-run"Nothing
(Value
"TIME") [quote
| Perform a trial run at the specified time but don't actually do anything. |] ,Option
"quiet" (Just
'q')Empty
[quote
| Supress normal output. |] ,Argument
"filename" [quote
| The file you want to frobnicate. |] ])executeWith
context program
which, if you build that into an executable called snippet
and invoke it
with --help
, would result in:
$ ./snippet --help Usage: snippet [OPTIONS] filename Available options: -h, --host Specify an alternate host to connect to when performing the frobnication. The default is "localhost". -p, --port Specify an alternate port to connect to when frobnicating. --dry-run=TIME Perform a trial run at the specified time but don't actually do anything. -q, --quiet Supress normal output. -v, --verbose Turn on event tracing. By default the logging stream will go to standard output on your terminal. --debug Turn on debug level logging. Implies --verbose. Required arguments: filename The file you want to frobnicate. $ |
For information on how to use the multi-line string literals shown here,
see quote
in Core.Text.Utilities.
complex :: [Commands] -> Config Source #
Declare a complex configuration (implying a larger tool with various "[sub]commands" or "modes"} for a program. You can specify global options applicable to all commands, a list of commands, and environment variables that will be honoured by the program. Each command can have a list of local options and arguments as needed. For example:
program ::Program
MusicAppStatus () program = ... main ::IO
() main = do context <-configure
(fromPackage
version)mempty
(complex
[Global
[Option
"station-name"Nothing
(Value
"NAME") [quote
| Specify an alternate radio station to connect to when performing actions. The default is "BBC Radio 1". |] ,Variable
"PLAYER_FORCE_HEADPHONES" [quote
| If set to1
, override the audio subsystem to force output to go to the user's headphone jack. |] ] ,Command
"play" "Play the music." [Option
"repeat"Nothing
Empty
[quote
| Request that they play the same song over and over and over again, simulating the effect of listening to a Top 40 radio station. |] ] ,Command
"rate" "Vote on whether you like the song or not." [Option
"academic"Nothing
Empty
[quote
| The rating you wish to apply, from A+ to F. This is the default, so there is no reason whatsoever to specify this. But some people are obsessive, compulsive, and have time on their hands. |] ,Option
"numeric"Nothing
Empty
[quote
| Specify a score as a number from 0 to 100 instead of an academic style letter grade. Note that negative values are not valid scores, despite how vicerally satisfying that would be for music produced in the 1970s. |] ,Option
"unicode" (Just
'c')Empty
[quote
| Instead of a score, indicate your rating with a single character. This allows you to use emoji, so that you can rate a piece '💩', as so many songs deserve. |] ,Argument
"score" [quote
| The rating you wish to apply. |] ] ])executeWith
context program
is a program with one global option (in addition to the default ones) [and
an environment variable] and two commands: play
, with one option; and
rate
, with two options and a required argument. It also is set up to
carry its top-level application state around in a type called
MusicAppStatus
(implementing Monoid
and so initialized here with
mempty
. This is a good pattern to use given we are so early in the
program's lifetime).
The resultant program could be invoked as in these examples:
$ ./player --station-name="KBBL-FM 102.5" play $
$ ./player -v rate --numeric 76 $
For information on how to use the multi-line string literals shown here,
see quote
in Core.Text.Utilities.
data Parameters Source #
Result of having processed the command-line and the environment. You get at
the parsed command-line options and arguments by calling
getCommandLine
within a
Program
block.
Each option and mandatory argument parsed from the command-line is either
standalone (in the case of switches and flags, such as --quiet
) or has an
associated value. In the case of options the key is the name of the option,
and for arguments it is the implicit name specified when setting up the
program. For example, in:
$ ./submit --username=gbmh GraceHopper_Resume.pdf
the option has parameter name "username
" and value "gmbh
"; the
argument has parameter name "filename" (assuming that is what was
declared in the Argument
entry) and a value being the Admiral's CV. This
would be returned as:
Parameters
Nothing
[("username","gbmh"), ("filename","GraceHopper_Resume.pdf")] []
The case of a complex command such as git or stack, you get the specific mode chosen by the user returned in the first position:
$ missiles launch --all
would be parsed as:
Parameters
(Just
"launch") [("all",Empty)] []
Instances
Eq Parameters Source # | |
Defined in Core.Program.Arguments (==) :: Parameters -> Parameters -> Bool # (/=) :: Parameters -> Parameters -> Bool # | |
Show Parameters Source # | |
Defined in Core.Program.Arguments showsPrec :: Int -> Parameters -> ShowS # show :: Parameters -> String # showList :: [Parameters] -> ShowS # |
data ParameterValue Source #
Individual parameters read in off the command-line can either have a value (in the case of arguments and options taking a value) or be empty (in the case of options that are just flags).
Instances
Eq ParameterValue Source # | |
Defined in Core.Program.Arguments (==) :: ParameterValue -> ParameterValue -> Bool # (/=) :: ParameterValue -> ParameterValue -> Bool # | |
Show ParameterValue Source # | |
Defined in Core.Program.Arguments showsPrec :: Int -> ParameterValue -> ShowS # show :: ParameterValue -> String # showList :: [ParameterValue] -> ShowS # | |
IsString ParameterValue Source # | |
Defined in Core.Program.Arguments fromString :: String -> ParameterValue # |
Options and Arguments
The name of an option, command, or agument (omitting the "--
" prefix in
the case of options). This identifier will be used to generate usage text
in response to --help
and by you later when retreiving the values of the
supplied parameters after the program has initialized.
Turn on OverloadedStrings
when specifying configurations, obviously.
Instances
Eq LongName Source # | |
Ord LongName Source # | |
Defined in Core.Program.Arguments | |
Show LongName Source # | |
IsString LongName Source # | |
Defined in Core.Program.Arguments fromString :: String -> LongName # | |
Hashable LongName Source # | |
Defined in Core.Program.Arguments | |
Pretty LongName Source # | |
Defined in Core.Program.Arguments | |
Key LongName Source # | |
Defined in Core.Program.Arguments |
type Description = Rope Source #
The description of an option, command, or environment variable (for use
when rendering usage information in response to --help
on the
command-line).
Declaration of an optional switch or mandatory argument expected by a program.
Option
takes a long name for the option, a short single character
abbreviation if offered for convenience, whether or not the option takes a
value (and what label to show in help output) and a description for use
when displaying usage via --help
.
Argument
indicates a mandatory argument and takes the long name used
to identify the parsed value from the command-line, and likewise a
description for --help
output.
By convention option and argument names are both lower case. If the identifier is two or more words they are joined with a hyphen. Examples:
[Option
"quiet" (Just
'q')Empty
"Keep the noise to a minimum." ,Option
"dry-run"Nothing
(Value
"TIME") "Run a simulation of what would happen at the specified time." ,Argument
"username" "The user to delete from the system." ]
By convention a description is one or more complete sentences each of which ends with a full stop. For options that take values, use upper case when specifying the label to be used in help output.
Variable
declares an environment variable that, if present, will be
read by the program and stored in its runtime context. By convention these
are upper case. If the identifier is two or more words they are joined
with an underscore:
[ ...
, Variable
"CRAZY_MODE" "Specify how many crazies to activate."
, ...
]
Programs with Commands
Description of the command-line structure of a program which has "commands" (sometimes referred to as "subcommands") representing different modes of operation. This is familiar from tools like git and docker.
Internals
parseCommandLine :: Config -> [String] -> Either InvalidCommandLine Parameters Source #
Given a program configuration schema and the command-line arguments, process them into key/value pairs in a Parameters object.
This results in InvalidCommandLine
on the left side if one of the passed
in options is unrecognized or if there is some other problem handling
options or arguments (because at that point, we want to rabbit right back
to the top and bail out; there's no recovering).
This isn't something you'll ever need to call directly; it's exposed for
testing convenience. This function is invoked when you call
configure
or execute
(which
calls configure
with a default Config
when initializing).
data InvalidCommandLine Source #
Different ways parsing a simple or complex command-line can fail.
InvalidOption String | Something was wrong with the way the user specified [usually a short] option. |
UnknownOption String | User specified an option that doesn't match any in the supplied configuration. |
MissingArgument LongName | Arguments are mandatory, and this one is missing. |
UnexpectedArguments [String] | Arguments are present we weren't expecting. |
UnknownCommand String | In a complex configuration, user specified a command that doesn't match any in the configuration. |
NoCommandFound | In a complex configuration, user didn't specify a command. |
HelpRequest (Maybe LongName) | In a complex configuration, usage information was requested with |
VersionRequest | Display of the program version requested with |
Instances
Eq InvalidCommandLine Source # | |
Defined in Core.Program.Arguments (==) :: InvalidCommandLine -> InvalidCommandLine -> Bool # (/=) :: InvalidCommandLine -> InvalidCommandLine -> Bool # | |
Show InvalidCommandLine Source # | |
Defined in Core.Program.Arguments showsPrec :: Int -> InvalidCommandLine -> ShowS # show :: InvalidCommandLine -> String # showList :: [InvalidCommandLine] -> ShowS # | |
Exception InvalidCommandLine Source # | |
Defined in Core.Program.Arguments |