Skip to content

Commit

Permalink
Parse configuration file from current directory for additional flags (#…
Browse files Browse the repository at this point in the history
…197)

* feature: Parse configuration file from current directory for additional flags

* fix: Use readFile instead of readFile' for GHC 8.10 on ubuntu-latest
  • Loading branch information
aloussase authored Oct 18, 2024
1 parent 8add769 commit 030fbda
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 31 deletions.
137 changes: 106 additions & 31 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Options.Applicative
import Paths_dotenv (version)

import Configuration.Dotenv (Config (..), defaultConfig, loadFile)
import System.Directory (doesFileExist)
import System.Exit (exitWith)
import System.Process (system)

Expand All @@ -26,9 +27,42 @@ data Options = Options
, args :: [String]
} deriving (Show)

data Flags = Flags
{ flagDotenvFiles :: [String]
, flagDotenvExampleFiles :: [String]
, flagOverride :: Bool
, flagVerbose :: Bool
, flagDryRun :: Bool
, flagDuplicates :: Bool
}

defaultFlags :: Flags
defaultFlags = Flags
{ flagDotenvFiles = []
, flagDotenvExampleFiles = []
, flagOverride = False
, flagVerbose = False
, flagDryRun = False
, flagDuplicates = False
}

applyFlags :: Options -> Flags -> Options
applyFlags options flags = Options
{ dotenvFiles = dotenvFiles options <> flagDotenvFiles flags
, dotenvExampleFiles = dotenvExampleFiles options <> flagDotenvExampleFiles flags
, override = override options || flagOverride flags
, verbose = verbose options || flagVerbose flags
, dryRun = dryRun options || flagDryRun flags
, duplicates = duplicates options || flagDuplicates flags
, program = program options
, args = args options
}

main :: IO ()
main = do
Options{..} <- execParser opts
options <- execParser $ mkOpts config
flags <- loadFlagsFromConfig
let Options{..} = applyFlags options flags
let configDotenv =
Config
{ configExamplePath = dotenvExampleFiles
Expand All @@ -46,45 +80,86 @@ main = do
if configDryRun configDotenv
then putStrLn "[INFO]: Dry run mode enabled. Not executing the program."
else system (program ++ concatMap (" " ++) args) >>= exitWith
where
opts = info (helper <*> versionOption <*> config)
( fullDesc
<> progDesc "Runs PROGRAM after loading options from FILE"
<> header "dotenv - loads options from dotenv files" )
versionOption =
infoOption

mkOpts :: Parser a -> ParserInfo a
mkOpts p = info (helper <*> versionOption <*> p)
( fullDesc
<> progDesc "Runs PROGRAM after loading options from FILE"
<> header "dotenv - loads options from dotenv files" )
where
versionOption = infoOption
(showVersion version)
(long "version" <> short 'v' <> help "Show version of the program")

config :: Parser Options
config = Options
<$> many (strOption (
long "dotenv"
<> short 'f'
<> metavar "DOTENV"
<> help "File to read for environmental variables" ))
<$> dotenvFileOption
<*> exampleFileOption
<*> overloadOption
<*> verboseOption
<*> dryRunOption
<*> noDuplicatesOption
<*> argument str (metavar "PROGRAM")
<*> many (argument str (metavar "ARG"))

<*> many (strOption (
long "example"
<> short 'x'
<> metavar "DOTENV_EXAMPLE"
<> help "File to read for needed environmental variables" ))
dotenvFileOption :: Parser [String]
dotenvFileOption = many
( strOption (
long "dotenv"
<> short 'f'
<> metavar "DOTENV"
<> help "File to read for environmental variables" ))

<*> switch ( long "overload"
<> short 'o'
<> help "Specify this flag to override existing variables" )
exampleFileOption :: Parser [FilePath]
exampleFileOption = many
( strOption (
long "example"
<> short 'x'
<> metavar "DOTENV_EXAMPLE"
<> help "File to read for needed environmental variables" ))

<*> switch ( long "verbose"
<> help "Specify this flag to print out the variables loaded and other useful insights" )
overloadOption :: Parser Bool
overloadOption = switch
( long "overload"
<> short 'o'
<> help "Specify this flag to override existing variables" )

<*> switch ( long "dry-run"
<> help "Specify this flag to print out the variables loaded without executing the program" )
verboseOption :: Parser Bool
verboseOption = switch
( long "verbose"
<> help "Specify this flag to print out the variables loaded and other useful insights" )

<*> flag True False ( long "no-dups"
<> short 'D'
<> help "Specify this flag to forbid duplicate variables"
)
dryRunOption :: Parser Bool
dryRunOption = switch
( long "dry-run"
<> help "Specify this flag to print out the variables loaded without executing the program" )

<*> argument str (metavar "PROGRAM")
noDuplicatesOption :: Parser Bool
noDuplicatesOption = flag True False
( long "no-dups"
<> short 'D'
<> help "Specify this flag to forbid duplicate variables" )

<*> many (argument str (metavar "ARG"))
flagsP :: Parser Flags
flagsP = Flags
<$> dotenvFileOption
<*> exampleFileOption
<*> overloadOption
<*> verboseOption
<*> dryRunOption
<*> noDuplicatesOption

configFile :: FilePath
configFile = "dotenv.config"

loadFlagsFromConfig :: IO Flags
loadFlagsFromConfig = do
configExists <- doesFileExist configFile
if not configExists then return defaultFlags
else do
arguments <- words <$> readFile configFile
case execParserPure defaultPrefs (mkOpts flagsP) arguments of
result@(Failure _) -> do
putStrLn "There were errors while parsing the configuration file"
handleParseResult result
result -> handleParseResult result
1 change: 1 addition & 0 deletions dotenv.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ executable dotenv
, megaparsec
, process
, text
, directory
other-modules: Paths_dotenv

hs-source-dirs: app
Expand Down

0 comments on commit 030fbda

Please sign in to comment.