module Buffet
  ( main
  ) where

import qualified Buffet.Facade as Facade
import qualified Control.Applicative as Applicative
import qualified Data.Foldable as Foldable
import qualified Options.Applicative as Options
import qualified Options.Applicative.Help.Pretty as Pretty
import Prelude
  ( FilePath
  , IO
  , Maybe(Just)
  , String
  , ($)
  , (.)
  , (<$>)
  , (<*>)
  , (>>=)
  , concatMap
  , fmap
  , mconcat
  , words
  )

main :: IO ()
main :: IO ()
main = ParserInfo Command -> IO Command
forall a. ParserInfo a -> IO a
Options.execParser ParserInfo Command
root IO Command -> (Command -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Command -> IO ()
Facade.get

root :: Options.ParserInfo Facade.Command
root :: ParserInfo Command
root =
  Parser Command -> InfoMod Command -> ParserInfo Command
forall a. Parser a -> InfoMod a -> ParserInfo a
Options.info Parser Command
parser (InfoMod Command -> ParserInfo Command)
-> InfoMod Command -> ParserInfo Command
forall a b. (a -> b) -> a -> b
$ String -> InfoMod Command
forall a. String -> InfoMod a
Options.progDesc String
"Assembles many Dockerfiles in one."
  where
    parser :: Parser Command
parser = Parser ((Command -> Command) -> Command -> Command)
forall a. Parser (a -> a)
versionOption Parser ((Command -> Command) -> Command -> Command)
-> Parser (Command -> Command) -> Parser (Command -> Command)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (Command -> Command)
forall a. Parser (a -> a)
Options.helper Parser (Command -> Command) -> Parser Command -> Parser Command
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Command
raw
    raw :: Parser Command
raw =
      Mod CommandFields Command -> Parser Command
forall a. Mod CommandFields a -> Parser a
Options.hsubparser (Mod CommandFields Command -> Parser Command)
-> Mod CommandFields Command -> Parser Command
forall a b. (a -> b) -> a -> b
$
      [Mod CommandFields Command] -> Mod CommandFields Command
forall a. Monoid a => [a] -> a
mconcat
        [ String -> ParserInfo Command -> Mod CommandFields Command
forall a. String -> ParserInfo a -> Mod CommandFields a
Options.command String
"assemble" ParserInfo Command
assemble
        , String -> ParserInfo Command -> Mod CommandFields Command
forall a. String -> ParserInfo a -> Mod CommandFields a
Options.command String
"document" ParserInfo Command
document
        , String -> ParserInfo Command -> Mod CommandFields Command
forall a. String -> ParserInfo a -> Mod CommandFields a
Options.command String
"parse" ParserInfo Command
parse
        , String -> ParserInfo Command -> Mod CommandFields Command
forall a. String -> ParserInfo a -> Mod CommandFields a
Options.command String
"test" ParserInfo Command
test
        ]

versionOption :: Options.Parser (a -> a)
versionOption :: Parser (a -> a)
versionOption =
  String -> Mod OptionFields (a -> a) -> Parser (a -> a)
forall a. String -> Mod OptionFields (a -> a) -> Parser (a -> a)
Options.infoOption String
"Buffet 1.0.1" (Mod OptionFields (a -> a) -> Parser (a -> a))
-> Mod OptionFields (a -> a) -> Parser (a -> a)
forall a b. (a -> b) -> a -> b
$
  [Mod OptionFields (a -> a)] -> Mod OptionFields (a -> a)
forall a. Monoid a => [a] -> a
mconcat
    [String -> Mod OptionFields (a -> a)
forall (f :: * -> *) a. HasName f => String -> Mod f a
Options.long String
"version", Maybe Doc -> Mod OptionFields (a -> a)
forall (f :: * -> *) a. Maybe Doc -> Mod f a
Options.helpDoc (Maybe Doc -> Mod OptionFields (a -> a))
-> Maybe Doc -> Mod OptionFields (a -> a)
forall a b. (a -> b) -> a -> b
$ Doc -> Maybe Doc
forall a. a -> Maybe a
Just Doc
versionHelp, Mod OptionFields (a -> a)
forall (f :: * -> *) a. Mod f a
Options.hidden]
  where
    versionHelp :: Doc
versionHelp =
      [String] -> Doc
paragraph
        [ String
"Prints the program name with version on stdout"
        , String
"and exits successfully"
        , String
"according to the GNU coding standards."
        ]

assemble :: Options.ParserInfo Facade.Command
assemble :: ParserInfo Command
assemble =
  Parser Command -> InfoMod Command -> ParserInfo Command
forall a. Parser a -> InfoMod a -> ParserInfo a
Options.info Parser Command
parser (InfoMod Command -> ParserInfo Command)
-> InfoMod Command -> ParserInfo Command
forall a b. (a -> b) -> a -> b
$
  String -> InfoMod Command
forall a. String -> InfoMod a
Options.progDesc String
"Assembles a Dockerfile from a list of Dockerfiles."
  where
    parser :: Parser Command
parser = (AssembleArguments -> Command)
-> Parser AssembleArguments -> Parser Command
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap AssembleArguments -> Command
Facade.Assemble (Parser AssembleArguments -> Parser Command)
-> Parser AssembleArguments -> Parser Command
forall a b. (a -> b) -> a -> b
$ String -> AssembleArguments
Facade.AssembleArguments (String -> AssembleArguments)
-> Parser String -> Parser AssembleArguments
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser String
menuOperand

menuOperand :: Options.Parser FilePath
menuOperand :: Parser String
menuOperand =
  ReadM String -> Mod ArgumentFields String -> Parser String
forall a. ReadM a -> Mod ArgumentFields a -> Parser a
Options.argument ReadM String
forall s. IsString s => ReadM s
Options.str (Mod ArgumentFields String -> Parser String)
-> Mod ArgumentFields String -> Parser String
forall a b. (a -> b) -> a -> b
$
  [Mod ArgumentFields String] -> Mod ArgumentFields String
forall a. Monoid a => [a] -> a
mconcat [String -> Mod ArgumentFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Options.metavar String
"menu_path", Maybe Doc -> Mod ArgumentFields String
forall (f :: * -> *) a. Maybe Doc -> Mod f a
Options.helpDoc (Maybe Doc -> Mod ArgumentFields String)
-> Maybe Doc -> Mod ArgumentFields String
forall a b. (a -> b) -> a -> b
$ Doc -> Maybe Doc
forall a. a -> Maybe a
Just Doc
menuHelp]

menuHelp :: Pretty.Doc
menuHelp :: Doc
menuHelp =
  [Doc] -> Doc
paragraphs
    [ [String] -> Doc
paragraph
        [ String
"File or folder that"
        , String
"lists the input Dockerfiles and"
        , String
"configures the output Dockerfile."
        ]
    , [String] -> Doc
paragraph
        [ String
"If the path is a file,"
        , String
"then it is a JSON or YAML file"
        , String
"with the following entries:"
        ]
    , [Doc] -> Doc
list
        [ [Doc] -> Doc
paragraphs
            [ [String] -> Doc
paragraph [String
"`copy_dummy_source_path`:"]
            , [String] -> Doc
paragraph
                [ String
"File or folder"
                , String
"that is added as a source path"
                , String
"to `COPY` instructions"
                , String
"because at least one source must exist."
                , String
"Default: \"/var/empty\""
                ]
            ]
        , [Doc] -> Doc
paragraphs
            [ [String] -> Doc
paragraph [String
"`option_to_dish`:"]
            , [String] -> Doc
paragraph
                [ String
"Map from `ARG` variable name to Dockerfile path."
                , String
"These Dockerfiles are assembled,"
                , String
"with their instructions conditioned"
                , String
"on the respective variable being nonempty."
                , String
"Default: {}"
                ]
            ]
        ]
    , [String] -> Doc
paragraph
        [ String
"If the path is a folder,"
        , String
"then the behavior is as if a file is given"
        , String
"with above defaults except for the following."
        , String
"`option_to_dish` is a map based on the path subfolders:"
        , String
"for each subfolder `x`, the map has an entry"
        , String
"with key `x` and value `x/Dockerfile`."
        ]
    ]

paragraphs :: [Pretty.Doc] -> Pretty.Doc
paragraphs :: [Doc] -> Doc
paragraphs = [Doc] -> Doc
Pretty.vsep

paragraph :: [String] -> Pretty.Doc
paragraph :: [String] -> Doc
paragraph =
  (Doc -> Doc -> Doc) -> Doc -> [Doc] -> Doc
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
Foldable.foldr Doc -> Doc -> Doc
(Pretty.</>) Doc
Pretty.line ([Doc] -> Doc) -> ([String] -> [Doc]) -> [String] -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Doc) -> [String] -> [Doc]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Doc
Pretty.text ([String] -> [Doc]) -> ([String] -> [String]) -> [String] -> [Doc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> [String]) -> [String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> [String]
words

list :: [Pretty.Doc] -> Pretty.Doc
list :: [Doc] -> Doc
list =
  [Doc] -> Doc
paragraphs ([Doc] -> Doc) -> ([Doc] -> [Doc]) -> [Doc] -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  (Doc -> Doc) -> [Doc] -> [Doc]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Doc
element -> Char -> Doc
Pretty.char Char
'-' Doc -> Doc -> Doc
Pretty.<+> Doc -> Doc
Pretty.align Doc
element)

document :: Options.ParserInfo Facade.Command
document :: ParserInfo Command
document = Parser Command -> InfoMod Command -> ParserInfo Command
forall a. Parser a -> InfoMod a -> ParserInfo a
Options.info Parser Command
parser (InfoMod Command -> ParserInfo Command)
-> InfoMod Command -> ParserInfo Command
forall a b. (a -> b) -> a -> b
$ String -> InfoMod Command
forall a. String -> InfoMod a
Options.progDesc String
"Generates documentation."
  where
    parser :: Parser Command
parser =
      (DocumentArguments -> Command)
-> Parser DocumentArguments -> Parser Command
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap DocumentArguments -> Command
Facade.Document (Parser DocumentArguments -> Parser Command)
-> Parser DocumentArguments -> Parser Command
forall a b. (a -> b) -> a -> b
$
      Maybe String -> String -> DocumentArguments
Facade.DocumentArguments (Maybe String -> String -> DocumentArguments)
-> Parser (Maybe String) -> Parser (String -> DocumentArguments)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser (Maybe String)
templateOption Parser (String -> DocumentArguments)
-> Parser String -> Parser DocumentArguments
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser String
menuOperand
    templateOption :: Options.Parser (Maybe FilePath)
    templateOption :: Parser (Maybe String)
templateOption =
      Parser String -> Parser (Maybe String)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Applicative.optional
        (Mod OptionFields String -> Parser String
forall s. IsString s => Mod OptionFields s -> Parser s
Options.strOption (Mod OptionFields String -> Parser String)
-> Mod OptionFields String -> Parser String
forall a b. (a -> b) -> a -> b
$
         [Mod OptionFields String] -> Mod OptionFields String
forall a. Monoid a => [a] -> a
mconcat
           [ String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
Options.long String
"template"
           , String -> Mod OptionFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Options.metavar String
"mustache_file"
           , Maybe Doc -> Mod OptionFields String
forall (f :: * -> *) a. Maybe Doc -> Mod f a
Options.helpDoc (Maybe Doc -> Mod OptionFields String)
-> Maybe Doc -> Mod OptionFields String
forall a b. (a -> b) -> a -> b
$ Doc -> Maybe Doc
forall a. a -> Maybe a
Just Doc
templateHelp
           ])
    templateHelp :: Doc
templateHelp =
      [String] -> Doc
paragraph
        [ String
"Mustache template to render (see https://mustache.github.io)."
        , String
"To print the template context instead, omit this option."
        ]

parse :: Options.ParserInfo Facade.Command
parse :: ParserInfo Command
parse =
  Parser Command -> InfoMod Command -> ParserInfo Command
forall a. Parser a -> InfoMod a -> ParserInfo a
Options.info Parser Command
parser (InfoMod Command -> ParserInfo Command)
-> InfoMod Command -> ParserInfo Command
forall a b. (a -> b) -> a -> b
$
  String -> InfoMod Command
forall a. String -> InfoMod a
Options.progDesc String
"Prints an intermediate representation for API usage."
  where
    parser :: Parser Command
parser = (ParseArguments -> Command)
-> Parser ParseArguments -> Parser Command
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ParseArguments -> Command
Facade.Parse (Parser ParseArguments -> Parser Command)
-> Parser ParseArguments -> Parser Command
forall a b. (a -> b) -> a -> b
$ String -> ParseArguments
Facade.ParseArguments (String -> ParseArguments)
-> Parser String -> Parser ParseArguments
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser String
menuOperand

test :: Options.ParserInfo Facade.Command
test :: ParserInfo Command
test = Parser Command -> InfoMod Command -> ParserInfo Command
forall a. Parser a -> InfoMod a -> ParserInfo a
Options.info Parser Command
parser (InfoMod Command -> ParserInfo Command)
-> InfoMod Command -> ParserInfo Command
forall a b. (a -> b) -> a -> b
$ String -> InfoMod Command
forall a. String -> InfoMod a
Options.progDesc String
"Performs health checks."
  where
    parser :: Parser Command
parser =
      (TestArguments -> Command)
-> Parser TestArguments -> Parser Command
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap TestArguments -> Command
Facade.Test (Parser TestArguments -> Parser Command)
-> Parser TestArguments -> Parser Command
forall a b. (a -> b) -> a -> b
$
      Maybe String -> String -> TestArguments
Facade.TestArguments (Maybe String -> String -> TestArguments)
-> Parser (Maybe String) -> Parser (String -> TestArguments)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser (Maybe String)
argumentsOption Parser (String -> TestArguments)
-> Parser String -> Parser TestArguments
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser String
menuOperand
    argumentsOption :: Options.Parser (Maybe FilePath)
    argumentsOption :: Parser (Maybe String)
argumentsOption =
      Parser String -> Parser (Maybe String)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Applicative.optional
        (Mod OptionFields String -> Parser String
forall s. IsString s => Mod OptionFields s -> Parser s
Options.strOption (Mod OptionFields String -> Parser String)
-> Mod OptionFields String -> Parser String
forall a b. (a -> b) -> a -> b
$
         [Mod OptionFields String] -> Mod OptionFields String
forall a. Monoid a => [a] -> a
mconcat
           [ String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
Options.long String
"arguments"
           , String -> Mod OptionFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Options.metavar String
"yaml_file"
           , Maybe Doc -> Mod OptionFields String
forall (f :: * -> *) a. Maybe Doc -> Mod f a
Options.helpDoc (Maybe Doc -> Mod OptionFields String)
-> Maybe Doc -> Mod OptionFields String
forall a b. (a -> b) -> a -> b
$ Doc -> Maybe Doc
forall a. a -> Maybe a
Just Doc
argumentsHelp
           ])
    argumentsHelp :: Doc
argumentsHelp =
      [String] -> Doc
paragraph
        [ String
"JSON or YAML file with a map that"
        , String
"sets the Docker build arguments."
        , String
"Health checks are only done for dishes in this map."
        ]