dotenv (empty) → 0.1.0.0
raw patch · 8 files changed
+274/−0 lines, 8 filesdep +basedep +hspecdep +optparse-applicativesetup-changed
Dependencies added: base, hspec, optparse-applicative, parsec, process
Files
- LICENSE +20/−0
- Setup.hs +2/−0
- dotenv.cabal +82/−0
- spec/Spec.hs +1/−0
- spec/fixtures/.dotenv +1/−0
- src/Configuration/Dotenv.hs +41/−0
- src/Configuration/Dotenv/Parse.hs +85/−0
- src/Main.hs +42/−0
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015 Justin Leitgeb++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ dotenv.cabal view
@@ -0,0 +1,82 @@+name: dotenv+version: 0.1.0.0+synopsis: Loads environment variables dotenv files++description:+ .+ In most applications,+ <http://12factor.net/config configuration should be separated from code>.+ While it usually works well to keep configuration in the+ environment, there are cases where you may want to store+ configuration in a file outside of version control.+ .+ "Dotenv" files have become popular for storing configuration,+ especially in development and test environments. In+ <https://github.com/bkeepers/dotenv Ruby>,+ <https://github.com/theskumar/python-dotenv Python> and+ <https://www.npmjs.com/package/dotenv Javascript> there are libraries+ to facilitate loading of configuration options from configuration+ files. This library loads configuration to environment variables for+ programs written in Haskell.+ .+ To use, call `loadFile` from your application:+ .+ > import Configuration.Dotenv+ > loadFile False "/my/dotenvfile"+ .+ This package also includes an executable that can be used+ to inspect the results of applying one or more Dotenv files+ to the environment, or for invoking your executables with+ an environment after one or more Dotenv files is applied.+ .+ See the <https://github.com/stackbuilders/dotenv-hs Github>+ page for more information on this package.+license: MIT+license-file: LICENSE+author: Justin Leitgeb+maintainer: justin@stackbuilders.com+copyright: 2015 Stack Builders Inc.+category: Configuration+build-type: Simple+extra-source-files: spec/fixtures/.dotenv+cabal-version: >=1.10++executable dotenv+ main-is: Main.hs+ -- other-modules:+ -- other-extensions:+ build-depends: base >=4.7 && <4.8+ , optparse-applicative >=0.11 && <0.12+ , parsec >= 3.1.0 && <= 3.2+ , process++ hs-source-dirs: src+ default-language: Haskell2010++library+ exposed-modules: Configuration.Dotenv.Parse+ , Configuration.Dotenv++ build-depends: base >=4.7 && <4.8+ , parsec >= 3.1.0 && <= 3.2++ hs-source-dirs: src+ default-language: Haskell2010+ ghc-options: -Wall+++test-suite dotenv-test+ type: exitcode-stdio-1.0+ hs-source-dirs: spec, src+ main-is: Spec.hs+ build-depends: base >=4.7 && <4.8+ , parsec >= 3.1.0 && <= 3.2++ , hspec++ default-language: Haskell2010+ ghc-options: -Wall++source-repository head+ type: git+ location: https://github.com/stackbuilders/dotenv-hs
+ spec/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ spec/fixtures/.dotenv view
@@ -0,0 +1,1 @@+DOTENV=true
+ src/Configuration/Dotenv.hs view
@@ -0,0 +1,41 @@+module Configuration.Dotenv (load, loadFile) where++import System.Environment (lookupEnv, setEnv)++import Configuration.Dotenv.Parse (configParser)++import Text.Parsec (parse)++-- | Loads the given list of options into the environment. Optionally+-- override existing variables with values from Dotenv files.+load ::+ Bool -- ^ Override existing settings?+ -> [(String, String)] -- ^ List of values to be set in environment+ -> IO ()+load override = mapM_ (applySetting override)++-- | Loads the options in the given file to the environment. Optionally+-- override existing variables with values from Dotenv files.+loadFile ::+ Bool -- ^ Override existing settings?+ -> FilePath -- ^ A file containing options to load into the environment+ -> IO ()+loadFile override f = do+ contents <- readFile f++ case parse configParser f contents of+ Left e -> error $ "Failed to read file" ++ show e+ Right options -> load override options+++applySetting :: Bool -> (String, String) -> IO ()+applySetting override (key, value) =+ if override then+ setEnv key value++ else do+ res <- lookupEnv key++ case res of+ Nothing -> setEnv key value+ Just _ -> return ()
+ src/Configuration/Dotenv/Parse.hs view
@@ -0,0 +1,85 @@+module Configuration.Dotenv.Parse (configParser) where++import Data.Maybe (catMaybes)++import Text.Parsec+ ((<|>), many, try, lookAhead, manyTill, char, anyChar, many1)++import Text.Parsec.String (Parser)++import Text.ParserCombinators.Parsec.Prim (GenParser)++import Text.ParserCombinators.Parsec.Char (space, newline, oneOf, noneOf)++import Control.Monad (liftM2)++import Text.Parsec.Combinator (eof)++import Control.Applicative ((<*), (*>), (<$>))++-- | Returns a parser for a Dotenv configuration file.+-- Accepts key and value arguments separated by "=".+-- Comments are allowed on lines by themselves and on+-- blank lines.+configParser :: Parser [(String, String)]+configParser = catMaybes <$> many lineWithArguments++lineWithArguments :: Parser (Maybe (String, String))+lineWithArguments =+ comment *> return Nothing+ <|> newline *> return Nothing+ <|> many1 (oneOf "\t ") *> return Nothing+ <|> Just <$> configurationOptionWithArguments++configurationOptionWithArguments :: Parser (String, String)+configurationOptionWithArguments = do+ _ <- many space++ keyword <- manyTill1 (noneOf "\n ") keywordArgSeparator++ arguments <- argumentParser++ return (keyword, arguments)++argumentParser :: Parser String+argumentParser = try quotedArgument <|> try unquotedArgument++-- | Based on a commented-string parser in:+-- http://hub.darcs.net/navilan/XMonadTasks/raw/Data/Config/Lexer.hs+quotedWith :: Char -> Parser String+quotedWith c =+ char c+ *> many chr+ <* char c+ where chr = esc <|> noneOf [c]+ esc = escape *> char c++quotedArgument :: Parser String+quotedArgument = quotedWith '\'' <|> quotedWith '\"'++unquotedArgument :: Parser String+unquotedArgument =+ many (noneOf " \t\n#") <* (try comment <|> try verticalSpace *> return () <|>+ lookAhead (try endOfLineOrInput))++comment :: Parser ()+comment =+ try (many verticalSpace *> char '#')+ *> manyTill anyChar endOfLineOrInput+ *> return ()++endOfLineOrInput :: Parser ()+endOfLineOrInput = newline *> return () <|> eof++manyTill1 :: GenParser tok st a -> GenParser tok st end -> GenParser tok st [a]+manyTill1 p end = liftM2 (:) p (manyTill p end)++keywordArgSeparator :: Parser ()+keywordArgSeparator =+ many verticalSpace *> char '=' *> many verticalSpace *> return ()++escape :: Parser Char+escape = char '\\'++verticalSpace :: Parser Char+verticalSpace = oneOf " \t"
+ src/Main.hs view
@@ -0,0 +1,42 @@+module Main where++import Options.Applicative++import Configuration.Dotenv (loadFile)++import System.Process (system)+import System.Exit (exitWith)++data Options = Options+ { files :: [String]+ , program :: String+ , overload :: Bool+ } deriving (Show)++main :: IO ()+main = execParser opts >>= dotEnv+ where+ opts = info (helper <*> config)+ ( fullDesc+ <> progDesc "Runs PROGRAM after loading options from FILE"+ <> header "dotenv - loads options from dotenv files" )++config :: Parser Options+config = Options+ <$> some (strOption (+ long "file"+ <> short 'f'+ <> metavar "FILE"+ <> help "File to read for options" ))++ <*> argument str (metavar "PROGRAM")++ <*> switch ( long "overload"+ <> short 'o'+ <> help "Specify this flag to override existing variables" )++dotEnv :: Options -> IO ()+dotEnv opts = do+ mapM_ (loadFile (overload opts)) (files opts)+ code <- system $ program opts+ exitWith code