{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE NoImplicitPrelude #-} module Biz.Cli ( Plan (..), main, Docopt.Docopt (..), Docopt.Arguments, Docopt.argument, Docopt.docopt, Docopt.getAllArgs, Docopt.getArg, Docopt.getArgWithDefault, Docopt.longOption, Docopt.shortOption, Docopt.command, has, ) where import Alpha import qualified Biz.Test as Test import qualified System.Console.Docopt as Docopt import qualified System.Environment as Environment -- | Plan is the main data structure that describes a CLI program. It's not the -- best name, but it works. This type is parameterized with `cfg` so you can -- load configuration from the environment and pass it into your Plan. data Plan cfg = Plan { -- | Usage info, shows when given --help help :: Docopt.Docopt, -- | The main function takes arguments and produces effects. Maybe it should -- also take `cfg` as an argument? move :: Docopt.Arguments -> IO (), -- | The test suite for the gram, invoked when 'test' is passed as the first -- argument to the program test :: Test.Tree, -- | Function for cleaning up any files or resources, presumably on -- shutdown. Can be just `pure` if you have nothing to tidy. tidy :: cfg -> IO () } -- | The entrypoint for CLI programs, use this in your own `main`. main :: Plan cfg -> IO () main Plan {..} = Environment.getArgs /> Docopt.parseArgs help +> \case Left err -> panic <| show err Right args -> if args `has` Docopt.command "test" then Test.run test else if args `has` Docopt.longOption "help" || args `has` Docopt.shortOption 'h' then Docopt.exitWithUsage help else move args has :: Docopt.Arguments -> Docopt.Option -> Bool has = Docopt.isPresent