hnix-0.13.0: src/Nix/Options/Parser.hs
{-# LANGUAGE TemplateHaskell #-}
-- | Code that configures presentation parser for the CLI options
module Nix.Options.Parser where
import Relude.Unsafe ( read )
import GHC.Err ( errorWithoutStackTrace )
import Data.Char ( isDigit )
import qualified Data.Text as Text
import Data.Time ( UTCTime
, defaultTimeLocale
, parseTimeOrError
)
import Nix.Options
import Options.Applicative hiding ( ParserResult(..) )
import Data.Version ( showVersion )
import Development.GitRev ( gitCommitDate
, gitBranch
, gitHash )
import Paths_hnix ( version )
decodeVerbosity :: Int -> Verbosity
decodeVerbosity 0 = ErrorsOnly
decodeVerbosity 1 = Informational
decodeVerbosity 2 = Talkative
decodeVerbosity 3 = Chatty
decodeVerbosity 4 = DebugInfo
decodeVerbosity _ = Vomit
argPair :: Mod OptionFields (Text, Text) -> Parser (Text, Text)
argPair =
option $
do
s <- str
maybe
(errorWithoutStackTrace "Format of --arg/--argstr in hnix is: name=expr")
(pure . second Text.tail . (`Text.splitAt` s))
(Text.findIndex (== '=') s)
nixOptions :: UTCTime -> Parser Options
nixOptions current =
Options <$>
(fromMaybe Informational <$>
optional
(option
(do
a <- str
bool
(fail "Argument to -v/--verbose must be a number")
(pure $ decodeVerbosity $ read a)
(all isDigit a)
)
( short 'v'
<> long "verbose"
<> help "Verbose output"
)
)
)
<*> switch
( long "trace"
<> help "Enable tracing code (even more can be seen if built with --flags=tracing)"
)
<*> switch
( long "thunks"
<> help "Enable reporting of thunk tracing as well as regular evaluation"
)
<*> switch
( long "values"
<> help "Enable reporting of value provenance in error messages"
)
<*> switch
( long "scopes"
<> help "Enable reporting of scopes in evaluation traces"
)
<*> optional
(strOption
( long "reduce"
<> help "When done evaluating, output the evaluated part of the expression to FILE"
)
)
<*> switch
( long "reduce-sets"
<> help "Reduce set members that aren't used; breaks if hasAttr is used"
)
<*> switch
( long "reduce-lists"
<> help "Reduce list members that aren't used; breaks if elemAt is used"
)
<*> switch
( long "parse"
<> help "Whether to parse the file (also the default right now)"
)
<*> switch
( long "parse-only"
<> help "Whether to parse only, no pretty printing or checking"
)
<*> switch
( long "find"
<> help "If selected, find paths within attr trees"
)
<*> optional
(strOption
( long "find-file"
<> help "Look up the given files in Nix's search path"
)
)
<*> switch
( long "strict"
<> help "When used with --eval, recursively evaluate list elements and attributes"
)
<*> switch
( long "eval"
<> help "Whether to evaluate, or just pretty-print"
)
<*> switch
( long "json"
<> help "Print the resulting value as an JSON representation"
)
<*> switch
( long "xml"
<> help "Print the resulting value as an XML representation"
)
<*> optional
(strOption
( short 'A'
<> long "attr"
<> help "Select an attribute from the top-level Nix expression being evaluated"
)
)
<*> many
(strOption
( short 'I'
<> long "include"
<> help "Add a path to the Nix expression search path"
)
)
<*> switch
( long "check"
<> help "Whether to check for syntax fails after parsing"
)
<*> optional
(strOption
( long "read"
<> help "Read in an expression tree from a binary cache"
)
)
<*> switch
( long "cache"
<> help "Write out the parsed expression tree to a binary cache"
)
<*> switch
( long "repl"
<> help "After performing any indicated actions, enter the REPL"
)
<*> switch
( long "ignore-fails"
<> help "Continue parsing files, even if there are fails"
)
<*> optional
(strOption
( short 'E'
<> long "expr"
<> help "Expression to parse or evaluate")
)
<*> many
(argPair
( long "arg"
<> help "Argument to pass to an evaluated lambda")
)
<*> many
(argPair
( long "argstr"
<> help "Argument string to pass to an evaluated lambda"
)
)
<*> optional
(strOption
( short 'f'
<> long "file"
<> help "Parse all of the files given in FILE; - means stdin"
)
)
<*> option
(parseTimeOrError True defaultTimeLocale "%Y/%m/%d %H:%M:%S" <$> str)
( long "now"
<> value current
<> help "Set current time for testing purposes"
)
<*> many
(strArgument
( metavar "FILE"
<> help "Path of file to parse"
)
)
-- 2020-09-12: CLI --version option mechanism is tied to meta modules specificly generated by Cabal. It is possible to use Template Haskell to resolve the version, as also a g
versionOpt :: Parser (a -> a)
versionOpt = shortVersionOpt <*> debugVersionOpt
where
shortVersionOpt :: Parser (a -> a)
shortVersionOpt =
infoOption
(showVersion version)
( long "version"
<> help "Show release version"
)
-- 2020-09-13: NOTE: Does not work for direct `nix-build`s, works for `nix-shell` `cabal` builds.
debugVersionOpt :: Parser (a -> a)
debugVersionOpt =
infoOption
( concat
[ "Version: ", showVersion version
, "\nCommit: ", $(gitHash)
, "\n date: ", $(gitCommitDate)
, "\n branch: ", $(gitBranch)
]
)
( long "long-version"
<> help "Show long debug version form"
)
nixOptionsInfo :: UTCTime -> ParserInfo Options
nixOptionsInfo current =
info
(helper <*> versionOpt <*> nixOptions current)
(fullDesc <> progDesc "" <> header "hnix")