{-# LANGUAGE NamedFieldPuns #-}
module CLI.Parsing
( parseArgs,
)
where
import CLI.Parsing.Internal
import CLI.Types.Env
import Common.Parsing.Core
import qualified Control.Exception as Ex
import qualified Data.Map.Strict as M
parseArgs :: [String] -> IO (Either ParseErr Env)
parseArgs :: [String] -> IO (Either ParseErr Env)
parseArgs args :: [String]
args =
case [String] -> ParseAnd Acc
pureParseArgs [String]
args of
ParseAnd (PFailure (Help _)) -> Either ParseErr Env -> IO (Either ParseErr Env)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ParseErr Env -> IO (Either ParseErr Env))
-> Either ParseErr Env -> IO (Either ParseErr Env)
forall a b. (a -> b) -> a -> b
$ ParseErr -> Either ParseErr Env
forall a b. a -> Either a b
Left (ParseErr -> Either ParseErr Env)
-> ParseErr -> Either ParseErr Env
forall a b. (a -> b) -> a -> b
$ String -> ParseErr
Help String
help
ParseAnd (PFailure (Err arg :: String
arg)) ->
Either ParseErr Env -> IO (Either ParseErr Env)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ParseErr Env -> IO (Either ParseErr Env))
-> Either ParseErr Env -> IO (Either ParseErr Env)
forall a b. (a -> b) -> a -> b
$ ParseErr -> Either ParseErr Env
forall a b. a -> Either a b
Left (ParseErr -> Either ParseErr Env)
-> ParseErr -> Either ParseErr Env
forall a b. (a -> b) -> a -> b
$ String -> ParseErr
Err (String -> ParseErr) -> String -> ParseErr
forall a b. (a -> b) -> a -> b
$ "Could not parse `" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
arg String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "`. Try --help."
ParseAnd (PSuccess acc :: Acc
acc) -> Acc -> IO (Either ParseErr Env)
accToEnv Acc
acc
accToEnv :: Acc -> IO (Either ParseErr Env)
accToEnv :: Acc -> IO (Either ParseErr Env)
accToEnv Acc {Maybe String
accLegend :: Acc -> Maybe String
accLegend :: Maybe String
accLegend, Maybe (RNonNegative Int)
accTimeout :: Acc -> Maybe (RNonNegative Int)
accTimeout :: Maybe (RNonNegative Int)
accTimeout, [Text]
accCommands :: Acc -> [Text]
accCommands :: [Text]
accCommands} =
case Maybe String
accLegend of
Nothing -> Either ParseErr Env -> IO (Either ParseErr Env)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ParseErr Env -> IO (Either ParseErr Env))
-> Either ParseErr Env -> IO (Either ParseErr Env)
forall a b. (a -> b) -> a -> b
$ Env -> Either ParseErr Env
forall a b. b -> Either a b
Right (Env -> Either ParseErr Env) -> Env -> Either ParseErr Env
forall a b. (a -> b) -> a -> b
$ Map Text Text -> Maybe (RNonNegative Int) -> [Text] -> Env
Env Map Text Text
forall k a. Map k a
M.empty Maybe (RNonNegative Int)
accTimeout [Text]
accCommands
Just path :: String
path -> do
Either SomeException String
res <- IO String -> IO (Either SomeException String)
forall e a. Exception e => IO a -> IO (Either e a)
Ex.try (String -> IO String
readFile String
path) :: IO (Either Ex.SomeException String)
Either ParseErr Env -> IO (Either ParseErr Env)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ParseErr Env -> IO (Either ParseErr Env))
-> Either ParseErr Env -> IO (Either ParseErr Env)
forall a b. (a -> b) -> a -> b
$ case Either SomeException String
res of
Left err :: SomeException
err -> ParseErr -> Either ParseErr Env
forall a b. a -> Either a b
Left (ParseErr -> Either ParseErr Env)
-> ParseErr -> Either ParseErr Env
forall a b. (a -> b) -> a -> b
$ String -> ParseErr
Err (String -> ParseErr) -> String -> ParseErr
forall a b. (a -> b) -> a -> b
$ "Error reading file " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String
forall a. Show a => a -> String
show String
path String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ": " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> (SomeException -> String
forall a. Show a => a -> String
show SomeException
err)
Right contents :: String
contents -> [Text] -> Maybe (RNonNegative Int) -> String -> Either ParseErr Env
mapStrToEnv [Text]
accCommands Maybe (RNonNegative Int)
accTimeout String
contents
help :: String
help :: String
help =
"\nUsage: cli-utils run-sh \"command 1\" \"command 2\" ... [OPTIONS]\n\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "Runs shell commands concurrently. Stdout is swallowed, so there is currently\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "no point to performing commands whose only effect is printing to stdout.\n\nOptions:\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> " --timeout=<seconds>\tNon-Negative integer. If we reach the timeout then all remaining\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\tcommands will be cancelled. If no timeout is given then the timeout is\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\tinfinite, i.e., we will keep running until all commands have finished.\n\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> " --legend=<string>\tPath to a legend file.\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\tLines are formatted <cmd_key>=<command value> (no angle brackets).\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\tEach line can be separated by as many new lines as desired, and comment lines start\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\twith a #. Command values themselves can include multiple commands delimited by\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\tcommas, and they may reference other commands. For instance, given a legend file:\n\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\t\tcmd1=echo \"command one\"\n\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\t\t# recursive references\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\t\tcmd2=cmd1\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\t\tcmd3=cmd2\n\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\t\tcmd4=command four\n\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\t\t# runs 3 and 4\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\t\tall=cmd3,cmd4,echo hi\n\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\tThen the command\n\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\t\tcli-utils run-sh --legend=path/to/legend all \"echo cat\"\n\n"
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> "\t\t\twill run `echo \"command one\"`, `command four`, `echo hi` and `echo cat` concurrently."