{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}

module Stack.Options.BuildParser
  ( buildOptsParser
  , flagsParser
  , targetsParser
  ) where

import qualified Data.Map as Map
import           Options.Applicative
import           Options.Applicative.Args
import           Options.Applicative.Builder.Extra
import           Stack.Options.Completion
import           Stack.Options.PackageParser ( readFlag )
import           Stack.Prelude
import           Stack.Types.Config

-- | Parser for CLI-only build arguments

buildOptsParser :: BuildCommand
                -> Parser BuildOptsCLI
buildOptsParser :: BuildCommand -> Parser BuildOptsCLI
buildOptsParser BuildCommand
cmd = [Text]
-> Bool
-> [Text]
-> Map ApplyCLIFlag (Map FlagName Bool)
-> BuildSubset
-> FileWatchOpts
-> Bool
-> [(String, [String])]
-> Bool
-> BuildCommand
-> Bool
-> BuildOptsCLI
BuildOptsCLI
  ([Text]
 -> Bool
 -> [Text]
 -> Map ApplyCLIFlag (Map FlagName Bool)
 -> BuildSubset
 -> FileWatchOpts
 -> Bool
 -> [(String, [String])]
 -> Bool
 -> BuildCommand
 -> Bool
 -> BuildOptsCLI)
-> Parser [Text]
-> Parser
     (Bool
      -> [Text]
      -> Map ApplyCLIFlag (Map FlagName Bool)
      -> BuildSubset
      -> FileWatchOpts
      -> Bool
      -> [(String, [String])]
      -> Bool
      -> BuildCommand
      -> Bool
      -> BuildOptsCLI)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser [Text]
targetsParser
  Parser
  (Bool
   -> [Text]
   -> Map ApplyCLIFlag (Map FlagName Bool)
   -> BuildSubset
   -> FileWatchOpts
   -> Bool
   -> [(String, [String])]
   -> Bool
   -> BuildCommand
   -> Bool
   -> BuildOptsCLI)
-> Parser Bool
-> Parser
     ([Text]
      -> Map ApplyCLIFlag (Map FlagName Bool)
      -> BuildSubset
      -> FileWatchOpts
      -> Bool
      -> [(String, [String])]
      -> Bool
      -> BuildCommand
      -> Bool
      -> BuildOptsCLI)
forall a b. Parser (a -> b) -> Parser a -> Parser b
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 String
"dry-run"
        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 String
"Don't build anything, just prepare to"
        )
  Parser
  ([Text]
   -> Map ApplyCLIFlag (Map FlagName Bool)
   -> BuildSubset
   -> FileWatchOpts
   -> Bool
   -> [(String, [String])]
   -> Bool
   -> BuildCommand
   -> Bool
   -> BuildOptsCLI)
-> Parser [Text]
-> Parser
     (Map ApplyCLIFlag (Map FlagName Bool)
      -> BuildSubset
      -> FileWatchOpts
      -> Bool
      -> [(String, [String])]
      -> Bool
      -> BuildCommand
      -> Bool
      -> BuildOptsCLI)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (   (\[Text]
x [Text]
y [Text]
z -> [[Text]] -> [Text]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Text]
x, [Text]
y, [Text]
z])
      ([Text] -> [Text] -> [Text] -> [Text])
-> Parser [Text] -> Parser ([Text] -> [Text] -> [Text])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text] -> [Text] -> Mod FlagFields [Text] -> Parser [Text]
forall a. a -> a -> Mod FlagFields a -> Parser a
flag
            []
            [Text
"-Wall", Text
"-Werror"]
            (  String -> Mod FlagFields [Text]
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"pedantic"
            Mod FlagFields [Text]
-> Mod FlagFields [Text] -> Mod FlagFields [Text]
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields [Text]
forall (f :: * -> *) a. String -> Mod f a
help String
"Turn on -Wall and -Werror"
            )
      Parser ([Text] -> [Text] -> [Text])
-> Parser [Text] -> Parser ([Text] -> [Text])
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Text] -> [Text] -> Mod FlagFields [Text] -> Parser [Text]
forall a. a -> a -> Mod FlagFields a -> Parser a
flag
            []
            [Text
"-O0"]
            (  String -> Mod FlagFields [Text]
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"fast"
            Mod FlagFields [Text]
-> Mod FlagFields [Text] -> Mod FlagFields [Text]
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields [Text]
forall (f :: * -> *) a. String -> Mod f a
help String
"Turn off optimizations (-O0)"
            )
      Parser ([Text] -> [Text]) -> Parser [Text] -> Parser [Text]
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Text -> Parser [Text]
forall a. Parser a -> Parser [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Mod OptionFields Text -> Parser Text
textOption
            (  String -> Mod OptionFields Text
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"ghc-options"
            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 String
"OPTIONS"
            Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> Completer -> Mod OptionFields Text
forall (f :: * -> *) a. HasCompleter f => Completer -> Mod f a
completer Completer
ghcOptsCompleter
            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 String
"Additional options passed to GHC"
            ))
      )
  Parser
  (Map ApplyCLIFlag (Map FlagName Bool)
   -> BuildSubset
   -> FileWatchOpts
   -> Bool
   -> [(String, [String])]
   -> Bool
   -> BuildCommand
   -> Bool
   -> BuildOptsCLI)
-> Parser (Map ApplyCLIFlag (Map FlagName Bool))
-> Parser
     (BuildSubset
      -> FileWatchOpts
      -> Bool
      -> [(String, [String])]
      -> Bool
      -> BuildCommand
      -> Bool
      -> BuildOptsCLI)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (Map ApplyCLIFlag (Map FlagName Bool))
flagsParser
  Parser
  (BuildSubset
   -> FileWatchOpts
   -> Bool
   -> [(String, [String])]
   -> Bool
   -> BuildCommand
   -> Bool
   -> BuildOptsCLI)
-> Parser BuildSubset
-> Parser
     (FileWatchOpts
      -> Bool
      -> [(String, [String])]
      -> Bool
      -> BuildCommand
      -> Bool
      -> BuildOptsCLI)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (   BuildSubset -> Mod FlagFields BuildSubset -> Parser BuildSubset
forall a. a -> Mod FlagFields a -> Parser a
flag' BuildSubset
BSOnlyDependencies
            (  String -> Mod FlagFields BuildSubset
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"dependencies-only"
            Mod FlagFields BuildSubset
-> Mod FlagFields BuildSubset -> Mod FlagFields BuildSubset
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields BuildSubset
forall (f :: * -> *) a. String -> Mod f a
help String
"A synonym for --only-dependencies"
            )
      Parser BuildSubset -> Parser BuildSubset -> Parser BuildSubset
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BuildSubset -> Mod FlagFields BuildSubset -> Parser BuildSubset
forall a. a -> Mod FlagFields a -> Parser a
flag' BuildSubset
BSOnlySnapshot
            (  String -> Mod FlagFields BuildSubset
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"only-snapshot"
            Mod FlagFields BuildSubset
-> Mod FlagFields BuildSubset -> Mod FlagFields BuildSubset
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields BuildSubset
forall (f :: * -> *) a. String -> Mod f a
help String
"Only build packages for the snapshot database, not the \
                    \local database"
            )
      Parser BuildSubset -> Parser BuildSubset -> Parser BuildSubset
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BuildSubset -> Mod FlagFields BuildSubset -> Parser BuildSubset
forall a. a -> Mod FlagFields a -> Parser a
flag' BuildSubset
BSOnlyDependencies
            (  String -> Mod FlagFields BuildSubset
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"only-dependencies"
            Mod FlagFields BuildSubset
-> Mod FlagFields BuildSubset -> Mod FlagFields BuildSubset
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields BuildSubset
forall (f :: * -> *) a. String -> Mod f a
help String
"Only build packages that are dependencies of targets on \
                    \the command line"
            )
      Parser BuildSubset -> Parser BuildSubset -> Parser BuildSubset
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BuildSubset -> Mod FlagFields BuildSubset -> Parser BuildSubset
forall a. a -> Mod FlagFields a -> Parser a
flag' BuildSubset
BSOnlyLocals
            (  String -> Mod FlagFields BuildSubset
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"only-locals"
            Mod FlagFields BuildSubset
-> Mod FlagFields BuildSubset -> Mod FlagFields BuildSubset
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields BuildSubset
forall (f :: * -> *) a. String -> Mod f a
help String
"Only build packages in the local database, fail if the \
                    \build plan includes the snapshot database"
            )
      Parser BuildSubset -> Parser BuildSubset -> Parser BuildSubset
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> BuildSubset -> Parser BuildSubset
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure BuildSubset
BSAll
      )
  Parser
  (FileWatchOpts
   -> Bool
   -> [(String, [String])]
   -> Bool
   -> BuildCommand
   -> Bool
   -> BuildOptsCLI)
-> Parser FileWatchOpts
-> Parser
     (Bool
      -> [(String, [String])]
      -> Bool
      -> BuildCommand
      -> Bool
      -> BuildOptsCLI)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (   FileWatchOpts
-> Mod FlagFields FileWatchOpts -> Parser FileWatchOpts
forall a. a -> Mod FlagFields a -> Parser a
flag' FileWatchOpts
FileWatch
            (  String -> Mod FlagFields FileWatchOpts
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"file-watch"
            Mod FlagFields FileWatchOpts
-> Mod FlagFields FileWatchOpts -> Mod FlagFields FileWatchOpts
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields FileWatchOpts
forall (f :: * -> *) a. String -> Mod f a
help String
"Watch for changes in local files and automatically \
                    \rebuild. Ignores files in VCS boring/ignore file"
            )
      Parser FileWatchOpts
-> Parser FileWatchOpts -> Parser FileWatchOpts
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> FileWatchOpts
-> Mod FlagFields FileWatchOpts -> Parser FileWatchOpts
forall a. a -> Mod FlagFields a -> Parser a
flag' FileWatchOpts
FileWatchPoll
            (  String -> Mod FlagFields FileWatchOpts
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"file-watch-poll"
            Mod FlagFields FileWatchOpts
-> Mod FlagFields FileWatchOpts -> Mod FlagFields FileWatchOpts
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields FileWatchOpts
forall (f :: * -> *) a. String -> Mod f a
help String
"Like --file-watch, but polling the filesystem instead of \
                    \using events"
            )
      Parser FileWatchOpts
-> Parser FileWatchOpts -> Parser FileWatchOpts
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> FileWatchOpts -> Parser FileWatchOpts
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure FileWatchOpts
NoFileWatch
      )
  Parser
  (Bool
   -> [(String, [String])]
   -> Bool
   -> BuildCommand
   -> Bool
   -> BuildOptsCLI)
-> Parser Bool
-> Parser
     ([(String, [String])]
      -> Bool -> BuildCommand -> Bool -> BuildOptsCLI)
forall a b. Parser (a -> b) -> Parser a -> Parser b
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 String
"watch-all"
        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 String
"Watch all local files not taking targets into account"
        )
  Parser
  ([(String, [String])]
   -> Bool -> BuildCommand -> Bool -> BuildOptsCLI)
-> Parser [(String, [String])]
-> Parser (Bool -> BuildCommand -> Bool -> BuildOptsCLI)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (String, [String]) -> Parser [(String, [String])]
forall a. Parser a -> Parser [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Mod OptionFields (String, [String]) -> Parser (String, [String])
cmdOption
        (  String -> Mod OptionFields (String, [String])
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"exec"
        Mod OptionFields (String, [String])
-> Mod OptionFields (String, [String])
-> Mod OptionFields (String, [String])
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (String, [String])
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"COMMAND [ARGUMENT(S)]"
        Mod OptionFields (String, [String])
-> Mod OptionFields (String, [String])
-> Mod OptionFields (String, [String])
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (String, [String])
forall (f :: * -> *) a. String -> Mod f a
help String
"Command and argument(s) to run after a successful build"
        ))
  Parser (Bool -> BuildCommand -> Bool -> BuildOptsCLI)
-> Parser Bool -> Parser (BuildCommand -> Bool -> BuildOptsCLI)
forall a b. Parser (a -> b) -> Parser a -> Parser b
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 String
"only-configure"
        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 String
"Only perform the configure step, not any builds. Intended for \
                \tool usage, may break when used on multiple packages at once!"
        )
  Parser (BuildCommand -> Bool -> BuildOptsCLI)
-> Parser BuildCommand -> Parser (Bool -> BuildOptsCLI)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> BuildCommand -> Parser BuildCommand
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure BuildCommand
cmd
  Parser (Bool -> BuildOptsCLI) -> Parser Bool -> Parser BuildOptsCLI
forall a b. Parser (a -> b) -> Parser a -> Parser b
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 String
"initial-build-steps"
        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 String
"For target packages, only run initial build steps needed for \
                \GHCi"
        Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> Mod FlagFields Bool
forall (f :: * -> *) a. Mod f a
internal
        )

targetsParser :: Parser [Text]
targetsParser :: Parser [Text]
targetsParser =
  Parser Text -> Parser [Text]
forall a. Parser a -> Parser [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Mod ArgumentFields Text -> Parser Text
textArgument
    (  String -> Mod ArgumentFields Text
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"TARGET"
    Mod ArgumentFields Text
-> Mod ArgumentFields Text -> Mod ArgumentFields Text
forall a. Semigroup a => a -> a -> a
<> Completer -> Mod ArgumentFields Text
forall (f :: * -> *) a. HasCompleter f => Completer -> Mod f a
completer Completer
targetCompleter
    Mod ArgumentFields Text
-> Mod ArgumentFields Text -> Mod ArgumentFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod ArgumentFields Text
forall (f :: * -> *) a. String -> Mod f a
help String
"If none specified, use all local packages. See \
            \https://docs.haskellstack.org/en/stable/build_command/#target-syntax \
            \for details."
    ))

flagsParser :: Parser (Map.Map ApplyCLIFlag (Map.Map FlagName Bool))
flagsParser :: Parser (Map ApplyCLIFlag (Map FlagName Bool))
flagsParser = (Map FlagName Bool -> Map FlagName Bool -> Map FlagName Bool)
-> [Map ApplyCLIFlag (Map FlagName Bool)]
-> Map ApplyCLIFlag (Map FlagName Bool)
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
(a -> a -> a) -> f (Map k a) -> Map k a
Map.unionsWith Map FlagName Bool -> Map FlagName Bool -> Map FlagName Bool
forall k a. Ord k => Map k a -> Map k a -> Map k a
Map.union
  ([Map ApplyCLIFlag (Map FlagName Bool)]
 -> Map ApplyCLIFlag (Map FlagName Bool))
-> Parser [Map ApplyCLIFlag (Map FlagName Bool)]
-> Parser (Map ApplyCLIFlag (Map FlagName Bool))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser (Map ApplyCLIFlag (Map FlagName Bool))
-> Parser [Map ApplyCLIFlag (Map FlagName Bool)]
forall a. Parser a -> Parser [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (ReadM (Map ApplyCLIFlag (Map FlagName Bool))
-> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
-> Parser (Map ApplyCLIFlag (Map FlagName Bool))
forall a. ReadM a -> Mod OptionFields a -> Parser a
option ReadM (Map ApplyCLIFlag (Map FlagName Bool))
readFlag
       (  String -> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"flag"
       Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
-> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
-> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
forall a. Semigroup a => a -> a -> a
<> Completer
-> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
forall (f :: * -> *) a. HasCompleter f => Completer -> Mod f a
completer Completer
flagCompleter
       Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
-> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
-> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"PACKAGE:[-]FLAG"
       Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
-> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
-> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (Map ApplyCLIFlag (Map FlagName Bool))
forall (f :: * -> *) a. String -> Mod f a
help String
"Override flags set in stack.yaml (applies to local packages \
               \and extra-deps)"
       ))