unbeliever-0.9.2.0: Opinionated Haskell Interoperability

Safe HaskellNone
LanguageHaskell2010

Core.Program.Arguments

Contents

Description

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

Setup

data Config Source #

The setup for parsing the command-line arguments of your program. You build a Config with simple or complex, and pass it to configure.

blank :: Config Source #

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 to 1, 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 # 
Instance details

Defined in Core.Program.Arguments

Show Parameters Source # 
Instance details

Defined in Core.Program.Arguments

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).

Constructors

Value String 
Empty 

Options and Arguments

newtype LongName Source #

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.

Constructors

LongName String 
Instances
Eq LongName Source # 
Instance details

Defined in Core.Program.Arguments

Ord LongName Source # 
Instance details

Defined in Core.Program.Arguments

Show LongName Source # 
Instance details

Defined in Core.Program.Arguments

IsString LongName Source # 
Instance details

Defined in Core.Program.Arguments

Hashable LongName Source # 
Instance details

Defined in Core.Program.Arguments

Methods

hashWithSalt :: Int -> LongName -> Int #

hash :: LongName -> Int #

Pretty LongName Source # 
Instance details

Defined in Core.Program.Arguments

Methods

pretty :: LongName -> Doc ann #

prettyList :: [LongName] -> Doc ann #

Key LongName Source # 
Instance details

Defined in Core.Program.Arguments

type ShortName = Char Source #

Single letter "short" options (omitting the "-" prefix, obviously).

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).

data Options Source #

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

data Commands Source #

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.

Constructors

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 --help, either globally or for the supplied command.

VersionRequest

Display of the program version requested with --version.