dotenv 0.2.0.0 → 0.3.0.0
raw patch · 8 files changed
+106/−48 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Configuration.Dotenv.Text: parseFile :: FilePath -> IO [(Text, Text)]
- Configuration.Dotenv: load :: Bool -> [(Text, Text)] -> IO ()
+ Configuration.Dotenv: load :: Bool -> [(String, String)] -> IO ()
- Configuration.Dotenv: parseFile :: FilePath -> IO [(Text, Text)]
+ Configuration.Dotenv: parseFile :: FilePath -> IO [(String, String)]
- Configuration.Dotenv.Parse: configParser :: Parser [(Text, Text)]
+ Configuration.Dotenv.Parse: configParser :: Parser [(String, String)]
Files
- CHANGELOG.md +9/−1
- dotenv.cabal +9/−4
- spec/Configuration/Dotenv/ParseSpec.hs +5/−4
- spec/Configuration/Dotenv/TextSpec.hs +29/−0
- spec/Configuration/DotenvSpec.hs +2/−4
- src/Configuration/Dotenv.hs +7/−12
- src/Configuration/Dotenv/Parse.hs +21/−23
- src/Configuration/Dotenv/Text.hs +24/−0
CHANGELOG.md view
@@ -1,4 +1,12 @@-## Dotenv 0.2.0.0+## Dotenv 0.3.0.0++* Reverted change to Data.Text in favor of String, for maintaining compatibility+ with common Haskell system libraries. Added separate interface for parsing a+ file into tuples containing Data.Text values. Thanks to Daisuke Fujimura+ (Github: fujimura).+* Fixed parsing of CRLF characters for Windows users.++## Dotenv 0.2.0.0 (deprecated) * Changed public interfaces to use Data.Text. * Added function `parseFile` to read dotenv file without modifying the
dotenv.cabal view
@@ -1,5 +1,5 @@ name: dotenv-version: 0.2.0.0+version: 0.3.0.0 synopsis: Loads environment variables from dotenv files homepage: https://github.com/stackbuilders/dotenv-hs description:@@ -47,6 +47,8 @@ main-is: Main.hs other-modules: Configuration.Dotenv Configuration.Dotenv.Parse+ , Configuration.Dotenv.Text+ -- other-extensions: build-depends: base >=4.5 && <5.0 , base-compat >= 0.4@@ -59,8 +61,9 @@ default-language: Haskell2010 library- exposed-modules: Configuration.Dotenv.Parse- , Configuration.Dotenv+ exposed-modules: Configuration.Dotenv+ , Configuration.Dotenv.Parse+ , Configuration.Dotenv.Text build-depends: base >=4.5 && <5.0 , base-compat >= 0.4@@ -77,15 +80,17 @@ hs-source-dirs: spec, src main-is: Spec.hs other-modules: Configuration.DotenvSpec+ , Configuration.Dotenv.TextSpec , Configuration.Dotenv.ParseSpec , Configuration.Dotenv+ , Configuration.Dotenv.Text , Configuration.Dotenv.Parse build-depends: base >=4.5 && <5.0 , base-compat >= 0.4 , megaparsec >= 4.2.0 && < 4.5.0- , text , hspec+ , text default-language: Haskell2010 ghc-options: -Wall
spec/Configuration/Dotenv/ParseSpec.hs view
@@ -1,5 +1,4 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE OverloadedStrings #-} module Configuration.Dotenv.ParseSpec (main, spec) where @@ -9,8 +8,6 @@ import Text.Megaparsec (ParseError, parse) -import qualified Data.Text as T- main :: IO () main = hspec spec @@ -34,6 +31,10 @@ parseConfig "FOO=\"escaped\\\"bar\"" `shouldBe` Right [("FOO", "escaped\"bar")] + it "supports CRLF line breaks" $+ parseConfig "FOO=bar\r\nbaz=fbb" `shouldBe`+ Right [("FOO", "bar"), ("baz", "fbb")]+ it "parses empty values" $ parseConfig "FOO=" `shouldBe` Right [("FOO", "")] @@ -89,5 +90,5 @@ isLeft ( Left _ ) = True isLeft _ = False -parseConfig :: T.Text -> Either ParseError [(T.Text, T.Text)]+parseConfig :: String -> Either ParseError [(String, String)] parseConfig = parse configParser "(unknown)"
+ spec/Configuration/Dotenv/TextSpec.hs view
@@ -0,0 +1,29 @@+module Configuration.Dotenv.TextSpec (main, spec) where++import Configuration.Dotenv.Text (parseFile)++import Test.Hspec++import System.Environment.Compat (lookupEnv, unsetEnv)+import Control.Monad (liftM)+import qualified Data.Text as T++{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}++main :: IO ()+main = hspec spec++spec :: Spec+spec =+ describe "parseFile" $ after_ (unsetEnv "DOTENV") $ do+ it "returns variables from a file without changing the environment" $ do+ lookupEnv "DOTENV" `shouldReturn` Nothing++ liftM head (parseFile "spec/fixtures/.dotenv") `shouldReturn`+ (T.pack "DOTENV", T.pack "true")++ lookupEnv "DOTENV" `shouldReturn` Nothing++ it "recognizes unicode characters" $+ liftM (!! 1) (parseFile "spec/fixtures/.dotenv") `shouldReturn`+ (T.pack "UNICODE_TEST", T.pack "Manabí")
spec/Configuration/DotenvSpec.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE OverloadedStrings #-}- module Configuration.DotenvSpec (main, spec) where import Configuration.Dotenv (load, loadFile, parseFile)@@ -9,7 +7,7 @@ import System.Environment.Compat (lookupEnv, setEnv, unsetEnv) import Control.Monad (liftM) -{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}+{-# ANN module "HLint: ignore Reduce duplication" #-} main :: IO () main = hspec spec@@ -64,7 +62,7 @@ it "returns variables from a file without changing the environment" $ do lookupEnv "DOTENV" `shouldReturn` Nothing - liftM head (parseFile "spec/fixtures/.dotenv") `shouldReturn`+ (liftM head $ parseFile "spec/fixtures/.dotenv") `shouldReturn` ("DOTENV", "true") lookupEnv "DOTENV" `shouldReturn` Nothing
src/Configuration/Dotenv.hs view
@@ -17,13 +17,11 @@ import Text.Megaparsec (parse) -import qualified Data.Text as T- -- | Loads the given list of options into the environment. Optionally -- override existing variables with values from Dotenv files. load :: Bool -- ^ Override existing settings?- -> [(T.Text, T.Text)] -- ^ List of values to be set in environment+ -> [(String, String)] -- ^ List of values to be set in environment -> IO () load override = mapM_ (applySetting override) @@ -39,25 +37,22 @@ -- the environment. parseFile :: FilePath -- ^ A file containing options to read- -> IO [(T.Text, T.Text)] -- ^ Variables contained in the file+ -> IO [(String, String)] -- ^ Variables contained in the file parseFile f = do contents <- readFile f - case parse configParser f (T.pack contents) of+ case parse configParser f contents of Left e -> error $ "Failed to read file" ++ show e Right options -> return options -applySetting :: Bool -> (T.Text, T.Text) -> IO ()+applySetting :: Bool -> (String, String) -> IO () applySetting override (key, value) = if override then- setEnv key' value'+ setEnv key value else do- res <- lookupEnv key'+ res <- lookupEnv key case res of- Nothing -> setEnv key' value'+ Nothing -> setEnv key value Just _ -> return ()-- where key' = T.unpack key- value' = T.unpack value
src/Configuration/Dotenv/Parse.hs view
@@ -15,74 +15,72 @@ module Configuration.Dotenv.Parse (configParser) where import Text.Megaparsec ((<?>), anyChar, char, eof, manyTill, try)-import Text.Megaparsec.Text (Parser)+import Text.Megaparsec.String (Parser) import Text.Megaparsec.Char- (digitChar, letterChar, newline, noneOf, oneOf)+ (digitChar, letterChar, eol, noneOf, oneOf) import Control.Applicative import Prelude import Data.Maybe (catMaybes)-import Control.Monad (liftM, liftM2)--import qualified Data.Text as T+import Control.Monad (liftM2) -- | 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 [(T.Text, T.Text)]+configParser :: Parser [(String, String)] configParser = catMaybes <$> many envLine <* eof -envLine :: Parser (Maybe (T.Text, T.Text))+envLine :: Parser (Maybe (String, String)) envLine = (comment <|> blankLine) *> return Nothing <|> Just <$> optionLine -blankLine :: Parser T.Text-blankLine = liftM T.pack (many verticalSpace <* newline) <?> "blank line"+blankLine :: Parser String+blankLine = many verticalSpace <* eol <?> "blank line" -optionLine :: Parser (T.Text, T.Text)+optionLine :: Parser (String, String) optionLine = liftM2 (,) (many verticalSpace *> variableName <* variableValueSeparator) value -- | Variables must start with a letter or underscore, and may contain -- letters, digits or '_' character after the first character.-variableName :: Parser T.Text-variableName = liftM T.pack (liftM2 (:) (letterChar <|> char '_')+variableName :: Parser String+variableName = liftM2 (:) (letterChar <|> char '_') (many (letterChar <|> char '_' <|> digitChar <?> unwords [ "valid non-leading shell variable character (alphanumeric,"- , "digit or underscore)" ])))+ , "digit or underscore)" ])) <?> unwords [ "shell variable name (letter or underscore followed" , "by alphanumeric characters or underscores)" ] -value :: Parser T.Text+value :: Parser String value = quotedValue <|> unquotedValue <?> "variable value" -quotedValue :: Parser T.Text+quotedValue :: Parser String quotedValue = (quotedWith '\'' <|> quotedWith '\"') <* (comment *> return () <|> many verticalSpace *> endOfLineOrInput) <?> "variable value surrounded with single or double quotes" -unquotedValue :: Parser T.Text+unquotedValue :: Parser String unquotedValue =- liftM T.pack (manyTill anyChar (liftM T.unpack comment <|> many verticalSpace <* endOfLineOrInput))+ manyTill anyChar (comment <|> many verticalSpace <* endOfLineOrInput) -- | Based on a commented-string parser in: -- http://hub.darcs.net/navilan/XMonadTasks/raw/Data/Config/Lexer.hs-quotedWith :: Char -> Parser T.Text-quotedWith c = liftM T.pack (char c *> many chr <* (char c <?> "closing quote character"))+quotedWith :: Char -> Parser String+quotedWith c = char c *> many chr <* (char c <?> "closing quote character") where chr = esc <|> noneOf [c] esc = escape *> char c <?> "escape character" -comment :: Parser T.Text-comment = liftM T.pack (try (many verticalSpace *> char '#')- *> manyTill anyChar endOfLineOrInput)+comment :: Parser String+comment = try (many verticalSpace *> char '#')+ *> manyTill anyChar endOfLineOrInput <?> "comment" endOfLineOrInput :: Parser ()-endOfLineOrInput = newline *> return () <|> eof+endOfLineOrInput = eol *> return () <|> eof variableValueSeparator :: Parser () variableValueSeparator =
+ src/Configuration/Dotenv/Text.hs view
@@ -0,0 +1,24 @@+-- |+-- Module : Configuration.Dotenv.Text+-- Copyright : © 2015–2016 Stack Builders Inc.+-- License : MIT+--+-- Maintainer : Stack Builders <hackage@stackbuilders.com>+-- Stability : experimental+-- Portability : portable+--+-- Provides a Data.Text interface for retrieving variables in a dotenv file.++module Configuration.Dotenv.Text (parseFile) where++import qualified Configuration.Dotenv++import qualified Data.Text as T+import Control.Arrow ((***))++-- | Parses the given dotenv file and returns values /without/ adding them to+-- the environment.+parseFile ::+ FilePath -- ^ A file containing options to read+ -> IO [(T.Text, T.Text)] -- ^ Variables contained in the file+parseFile f = map (T.pack *** T.pack) `fmap` Configuration.Dotenv.parseFile f