packages feed

argo-0.2022.1.15: source/library/Argo/Main.hs

module Argo.Main where

import qualified Argo
import qualified Argo.Type.Flag as Flag
import qualified Argo.Type.Settings as Settings
import qualified Argo.Vendor.Builder as Builder
import qualified Argo.Vendor.ByteString as ByteString
import qualified Control.Monad as Monad
import qualified Data.Version as Version
import qualified Paths_argo as This
import qualified System.Console.GetOpt as Console
import qualified System.Environment as Environment
import qualified System.Exit as Exit
import qualified System.IO as IO

main :: IO ()
main = do
    name <- Environment.getProgName
    arguments <- Environment.getArgs
    mainWith name arguments

mainWith :: String -> [String] -> IO ()
mainWith name arguments = do
    let ((warnings, errors), flags) = getFlags arguments
    mapM_ (IO.hPutStrLn IO.stderr) warnings
    mapM_ (IO.hPutStr IO.stderr) errors
    Monad.unless (null errors) Exit.exitFailure

    withSettings name flags $ \settings -> do
        contents <- ByteString.getContents
        value <- case Argo.decode contents of
            Left e -> fail e
            Right x -> pure (x :: Argo.Value)
        Builder.hPutBuilder IO.stdout
            $ Argo.encodeWith (Settings.indent settings) value

getFlags :: [String] -> (([String], [String]), [Flag.Flag])
getFlags arguments =
    let
        (flags, xs, ys, errors) =
            Console.getOpt' Console.Permute options arguments
        warnings =
            fmap (mappend "unknown argument " . quote) xs
                <> fmap (mappend "unknown option " . quote) ys
    in ((warnings, errors), flags)

withSettings :: String -> [Flag.Flag] -> (Settings.Settings -> IO ()) -> IO ()
withSettings name flags callback = do
    settings <- either fail pure
        $ Monad.foldM Settings.applyFlag Settings.initial flags
    if Settings.help settings
        then putStr
            $ Console.usageInfo (name <> " version " <> version) options
        else if Settings.version settings
            then putStrLn version
            else callback settings

quote :: String -> String
quote x = "`" <> x <> "'"

version :: String
version = Version.showVersion This.version

options :: [Console.OptDescr Flag.Flag]
options =
    [ Console.Option
        ['h', '?']
        ["help"]
        (Console.NoArg Flag.Help)
        "shows this help message and exits"
    , Console.Option
        ['v']
        ["version"]
        (Console.NoArg Flag.Version)
        "shows the version number and exits"
    , Console.Option
        ['s']
        ["spaces"]
        (Console.ReqArg Flag.Spaces "INT")
        "pretty-prints the output using INT sapces"
    , Console.Option
        ['t']
        ["tab"]
        (Console.NoArg Flag.Tab)
        "pretty-prints the output using tabs"
    ]