Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse configuration file from current directory for additional flags #197

Merged
merged 2 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 107 additions & 31 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
import Paths_dotenv (version)

import Configuration.Dotenv (Config (..), defaultConfig, loadFile)
import System.Directory (doesFileExist)
import System.Exit (exitWith)
import System.IO (readFile')

Check failure on line 17 in app/Main.hs

View workflow job for this annotation

GitHub Actions / GHC 8.10 on ubuntu-latest

Module ‘System.IO’ does not export ‘readFile'’
import System.Process (system)

data Options = Options
Expand All @@ -26,9 +28,42 @@
, 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 +81,86 @@
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
Loading