{-|
Module      : Headroom.Command
Description : Command line options processing
Copyright   : (c) 2019-2020 Vaclav Svejcar
License     : BSD-3
Maintainer  : vaclav.svejcar@gmail.com
Stability   : experimental
Portability : POSIX

Data types and functions for parsing command line options.
-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Headroom.Command
  ( Command(..)
  , commandParser
  )
where

import           Headroom.Meta                  ( buildVer )
import           Headroom.Types                 ( RunMode(..) )
import           Options.Applicative
import           RIO


-- | Application command.
data Command
  = Run [FilePath] [FilePath] [Text] RunMode Bool -- ^ /Run/ command
  | Gen Bool (Maybe Text)                         -- ^ /Generator/ command
    deriving (Int -> Command -> ShowS
[Command] -> ShowS
Command -> String
(Int -> Command -> ShowS)
-> (Command -> String) -> ([Command] -> ShowS) -> Show Command
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Command] -> ShowS
$cshowList :: [Command] -> ShowS
show :: Command -> String
$cshow :: Command -> String
showsPrec :: Int -> Command -> ShowS
$cshowsPrec :: Int -> Command -> ShowS
Show)

-- | Parses command line arguments.
commandParser :: ParserInfo Command
commandParser :: ParserInfo Command
commandParser = Parser Command -> InfoMod Command -> ParserInfo Command
forall a. Parser a -> InfoMod a -> ParserInfo a
info
  (Parser Command
commands Parser Command -> Parser (Command -> Command) -> Parser Command
forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> Parser (Command -> Command)
forall a. Parser (a -> a)
helper)
  (  InfoMod Command
forall a. InfoMod a
fullDesc
  InfoMod Command -> InfoMod Command -> InfoMod Command
forall a. Semigroup a => a -> a -> a
<> String -> InfoMod Command
forall a. String -> InfoMod a
progDesc "manage your source code license headers"
  InfoMod Command -> InfoMod Command -> InfoMod Command
forall a. Semigroup a => a -> a -> a
<> String -> InfoMod Command
forall a. String -> InfoMod a
header String
header'
  )
 where
  header' :: String
header' =
    "headroom v" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
buildVer String -> ShowS
forall a. Semigroup a => a -> a -> a
<> " :: https://github.com/vaclavsvejcar/headroom"
  commands :: Parser Command
commands   = Mod CommandFields Command -> Parser Command
forall a. Mod CommandFields a -> Parser a
subparser (Mod CommandFields Command
runCommand Mod CommandFields Command
-> Mod CommandFields Command -> Mod CommandFields Command
forall a. Semigroup a => a -> a -> a
<> Mod CommandFields Command
genCommand)
  runCommand :: Mod CommandFields Command
runCommand = String -> ParserInfo Command -> Mod CommandFields Command
forall a. String -> ParserInfo a -> Mod CommandFields a
command
    "run"
    (Parser Command -> InfoMod Command -> ParserInfo Command
forall a. Parser a -> InfoMod a -> ParserInfo a
info (Parser Command
runOptions Parser Command -> Parser (Command -> Command) -> Parser Command
forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> Parser (Command -> Command)
forall a. Parser (a -> a)
helper)
          (String -> InfoMod Command
forall a. String -> InfoMod a
progDesc "add or replace source code headers")
    )
  genCommand :: Mod CommandFields Command
genCommand = String -> ParserInfo Command -> Mod CommandFields Command
forall a. String -> ParserInfo a -> Mod CommandFields a
command
    "gen"
    (Parser Command -> InfoMod Command -> ParserInfo Command
forall a. Parser a -> InfoMod a -> ParserInfo a
info (Parser Command
genOptions Parser Command -> Parser (Command -> Command) -> Parser Command
forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> Parser (Command -> Command)
forall a. Parser (a -> a)
helper)
          (String -> InfoMod Command
forall a. String -> InfoMod a
progDesc "generate stub configuration and template files")
    )


runOptions :: Parser Command
runOptions :: Parser Command
runOptions =
  [String] -> [String] -> [Text] -> RunMode -> Bool -> Command
Run
    ([String] -> [String] -> [Text] -> RunMode -> Bool -> Command)
-> Parser [String]
-> Parser ([String] -> [Text] -> RunMode -> Bool -> Command)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser String -> Parser [String]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many
          (Mod OptionFields String -> Parser String
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
            (String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
long "source-path" Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short 's' Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar "PATH" Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. String -> Mod f a
help
              "path to source code file/directory"
            )
          )
    Parser ([String] -> [Text] -> RunMode -> Bool -> Command)
-> Parser [String] -> Parser ([Text] -> RunMode -> Bool -> Command)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser String -> Parser [String]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many
          (Mod OptionFields String -> Parser String
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
            (String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
long "template-path" Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short 't' Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar "PATH" Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. String -> Mod f a
help
              "path to header template file/directory"
            )
          )
    Parser ([Text] -> RunMode -> Bool -> Command)
-> Parser [Text] -> Parser (RunMode -> Bool -> Command)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Text -> Parser [Text]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many
          (Mod OptionFields Text -> Parser Text
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
            (String -> Mod OptionFields Text
forall (f :: * -> *) a. HasName f => String -> Mod f a
long "variables" Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields Text
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short 'v' Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Text
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar "KEY=VALUE" Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Text
forall (f :: * -> *) a. String -> Mod f a
help
              "values for template variables"
            )
          )
    Parser (RunMode -> Bool -> Command)
-> Parser RunMode -> Parser (Bool -> Command)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (   RunMode -> Mod FlagFields RunMode -> Parser RunMode
forall a. a -> Mod FlagFields a -> Parser a
flag'
            RunMode
Replace
            (String -> Mod FlagFields RunMode
forall (f :: * -> *) a. HasName f => String -> Mod f a
long "replace-headers" Mod FlagFields RunMode
-> Mod FlagFields RunMode -> Mod FlagFields RunMode
forall a. Semigroup a => a -> a -> a
<> Char -> Mod FlagFields RunMode
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short 'r' Mod FlagFields RunMode
-> Mod FlagFields RunMode -> Mod FlagFields RunMode
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields RunMode
forall (f :: * -> *) a. String -> Mod f a
help
              "force replace existing license headers"
            )
        Parser RunMode -> Parser RunMode -> Parser RunMode
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> RunMode -> Mod FlagFields RunMode -> Parser RunMode
forall a. a -> Mod FlagFields a -> Parser a
flag'
              RunMode
Drop
              (String -> Mod FlagFields RunMode
forall (f :: * -> *) a. HasName f => String -> Mod f a
long "drop-headers" Mod FlagFields RunMode
-> Mod FlagFields RunMode -> Mod FlagFields RunMode
forall a. Semigroup a => a -> a -> a
<> Char -> Mod FlagFields RunMode
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short 'd' Mod FlagFields RunMode
-> Mod FlagFields RunMode -> Mod FlagFields RunMode
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields RunMode
forall (f :: * -> *) a. String -> Mod f a
help
                "drop existing license headers only"
              )
        Parser RunMode -> Parser RunMode -> Parser RunMode
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> RunMode -> Parser RunMode
forall (f :: * -> *) a. Applicative f => a -> f a
pure RunMode
Add
        )
    Parser (Bool -> Command) -> Parser Bool -> Parser Command
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Mod FlagFields Bool -> Parser Bool
switch (String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long "debug" Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help "produce more verbose output")

genOptions :: Parser Command
genOptions :: Parser Command
genOptions =
  Bool -> Maybe Text -> Command
Gen
    (Bool -> Maybe Text -> Command)
-> Parser Bool -> Parser (Maybe Text -> Command)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Mod FlagFields Bool -> Parser Bool
switch
          (String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long "config-file" Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> Char -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short 'c' Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help
            "generate stub YAML config file to stdout"
          )
    Parser (Maybe Text -> Command)
-> Parser (Maybe Text) -> Parser Command
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Text -> Parser (Maybe Text)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional
          (Mod OptionFields Text -> Parser Text
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
            (String -> Mod OptionFields Text
forall (f :: * -> *) a. HasName f => String -> Mod f a
long "license" Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields Text
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short 'l' Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Text
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar "name:type" Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Text
forall (f :: * -> *) a. String -> Mod f a
help
              "generate template for license and file type"
            )
          )