diff --git a/changelog.d/5-internal/refactor-get-options b/changelog.d/5-internal/refactor-get-options new file mode 100644 index 0000000000..969db11f0b --- /dev/null +++ b/changelog.d/5-internal/refactor-get-options @@ -0,0 +1 @@ +Refactor getOptions diff --git a/libs/types-common/src/Util/Options.hs b/libs/types-common/src/Util/Options.hs index 823f9bcc68..d579c7fbb4 100644 --- a/libs/types-common/src/Util/Options.hs +++ b/libs/types-common/src/Util/Options.hs @@ -31,7 +31,6 @@ import Data.Yaml hiding (Parser) import Imports import Options.Applicative import Options.Applicative.Types -import System.Exit (die) import URI.ByteString import Util.Options.Common @@ -111,7 +110,14 @@ loadSecret (FilePathSecrets p) = do then over _Left show . decodeEither' <$> BS.readFile path else pure (Left "File doesn't exist") +-- | Get configuration options from the command line or configuration file. +-- +-- This uses the provided optparse-applicative parser, if given. In all cases, +-- it prepends a `config-file` option to the parser that accepts a file name. +-- When that option is found, the config file is used to get the options, +-- instead of the command line. getOptions :: + forall a. FromJSON a => -- | Program description String -> @@ -120,46 +126,40 @@ getOptions :: -- | Default config path, can be overridden with @--config-file@ FilePath -> IO a -getOptions desc pars defaultPath = do - path <- parseConfigPath defaultPath mkDesc - file <- doesFileExist path - case (file, pars) of - -- Config exists, we can just take options from there +getOptions desc mp defaultPath = do + (path, mOpts) <- + execParser $ + info + (optsOrConfigFile <**> helper) + (header desc <> fullDesc) + exists <- doesFileExist path + case (exists, mOpts) of + -- config file exists, take options from there (True, _) -> do - configFile <- decodeFileEither path - case configFile of + decodeFileEither path >>= \case Left e -> fail $ show e <> " while attempting to decode " - <> show path + <> path Right o -> pure o - -- Config doesn't exist but at least we have a CLI options parser - (False, Just p) -> do - execParser (info (helper <*> p) mkDesc) - -- No config, no parser :( - (False, Nothing) -> do - die $ "Config file at " ++ path ++ " does not exist. \n" - where - mkDesc :: InfoMod b - mkDesc = header desc <> fullDesc - -parseConfigPath :: FilePath -> InfoMod String -> IO String -parseConfigPath defaultPath desc = do - args <- getArgs - let result = - getParseResult $ - execParserPure defaultPrefs (info (helper <*> pathParser) desc) args - pure $ fromMaybe defaultPath result + -- config doesn't exist, take options from command line + (False, Just opts) -> pure opts + -- no config, no parser, just fail + (False, Nothing) -> + fail $ "Config file at " <> path <> " does not exist." where - pathParser :: Parser String - pathParser = - strOption $ - long "config-file" - <> short 'c' - <> help "Config file to load" - <> showDefault - <> value defaultPath + optsOrConfigFile :: Parser (FilePath, Maybe a) + optsOrConfigFile = + (,) + <$> strOption + ( long "config-file" + <> short 'c' + <> help "Config file to load" + <> showDefault + <> value defaultPath + ) + <*> sequenceA mp parseAWSEndpoint :: ReadM AWSEndpoint parseAWSEndpoint = readerAsk >>= maybe (error "Could not parse AWS endpoint") pure . fromByteString . fromString