load-env 0.1.1 → 0.1.2
raw patch · 6 files changed
+213/−58 lines, 6 filesdep −HUnitdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies removed: HUnit
Dependency ranges changed: base
API changes (from Hackage documentation)
Files
- LICENSE +1/−1
- load-env.cabal +52/−38
- src/LoadEnv.hs +1/−2
- src/LoadEnv/Parse.hs +8/−17
- test/LoadEnv/ParseSpec.hs +113/−0
- test/LoadEnvSpec.hs +38/−0
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2014, Pat Brisbin+Copyright (c) 2017, Pat Brisbin All rights reserved.
load-env.cabal view
@@ -1,42 +1,56 @@-name: load-env-version: 0.1.1-author: Pat Brisbin <pbrisbin@gmail.com>-maintainer: Pat Brisbin <pbrisbin@gmail.com>-license: BSD3-license-file: LICENSE-synopsis: Load environment variables from a file.-category: Configuration-description: Parse a .env file and load any declared variables into- the current process's environment. This allows for a- .env file to specify development-friendly defaults for- configuration values normally set in the deployment- environment.-cabal-version: >= 1.10-build-type: Simple+-- This file has been generated from package.yaml by hpack version 0.20.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 9c909afbd1a08e860e60320c5f83c51783e382789593a82de5798a86d1464c45 +name: load-env+version: 0.1.2+synopsis: Load environment variables from a file.+description: Parse a .env file and load any declared variables into the current process's environment. This allows for a .env file to specify development-friendly defaults for configuration values normally set in the deployment environment.+category: Configuration+homepage: https://github.com/pbrisbin/load-env#readme+bug-reports: https://github.com/pbrisbin/load-env/issues+author: Pat Brisbin <pbrisbin@gmail.com>+maintainer: Pat Brisbin <pbrisbin@gmail.com>+license: BSD3+license-file: LICENSE+build-type: Simple+cabal-version: >= 1.10++source-repository head+ type: git+ location: https://github.com/pbrisbin/load-env+ library- default-language: Haskell2010- hs-source-dirs: src- ghc-options: -Wall- exposed-modules: LoadEnv- , LoadEnv.Parse- build-depends: base >= 4.7.0 && < 5- , directory- , parsec+ hs-source-dirs:+ src+ ghc-options: -Wall+ build-depends:+ base >=4.8.0 && <5+ , directory+ , parsec+ exposed-modules:+ LoadEnv+ LoadEnv.Parse+ other-modules:+ Paths_load_env+ default-language: Haskell2010 test-suite spec- type: exitcode-stdio-1.0- default-language: Haskell2010- hs-source-dirs: test- ghc-options: -Wall- main-is: Spec.hs- build-depends: base- , load-env- , directory- , hspec- , HUnit- , parsec--source-repository head- type: git- location: https://github.com/pbrisbin/load-env+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ hs-source-dirs:+ test+ ghc-options: -Wall+ build-depends:+ base >=4.8.0 && <5+ , directory+ , hspec+ , load-env+ , parsec+ other-modules:+ LoadEnv.ParseSpec+ LoadEnvSpec+ Paths_load_env+ default-language: Haskell2010
src/LoadEnv.hs view
@@ -5,11 +5,10 @@ import Control.Monad (when)+import LoadEnv.Parse import System.Directory (doesFileExist) import System.Environment (setEnv) import Text.Parsec.String (parseFromFile)--import LoadEnv.Parse -- | --
src/LoadEnv/Parse.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} module LoadEnv.Parse ( Environment , Variable@@ -6,13 +5,8 @@ , parseVariable ) where -#if __GLASGOW_HASKELL__ < 710-import Control.Applicative ((<$>))-#endif- import Control.Monad (void) import Data.Maybe (catMaybes)- import Text.Parsec import Text.Parsec.String @@ -26,25 +20,22 @@ parseLine = possibly parseVariable possibly :: Parser a -> Parser (Maybe a)-possibly p = try (fmap Just p) <|> ignored+possibly p = try (Just <$> p) <|> ignored where- ignored = do- void $ manyTill anyToken newline- return Nothing+ ignored = Nothing <$ manyTill anyToken newline parseVariable :: Parser Variable parseVariable = do optional $ between spaces spaces $ string "export" i <- identifier- void $ char '='+ v <- char '=' *> value - v <- value void $ many $ oneOf " \t"- void $ newline+ void newline - return (i, v)+ pure (i, v) -- Environment variable names used by the utilities in the Shell and Utilities -- volume of IEEE Std 1003.1-2001 consist solely of uppercase letters, digits,@@ -58,13 +49,13 @@ x <- upper <|> underscore ys <- many $ upper <|> digit <|> underscore - return (x:ys)+ pure (x:ys) where underscore = char '_' value :: Parser String-value = quotedValue <|> unquotedValue <|> return ""+value = quotedValue <|> unquotedValue <|> pure "" quotedValue :: Parser String quotedValue = do@@ -76,4 +67,4 @@ unquotedValue = many1 $ try (escaped ' ') <|> noneOf "\"' \n" escaped :: Char -> Parser Char-escaped c = string ("\\" ++ [c]) >> return c+escaped c = c <$ string ("\\" ++ [c])
+ test/LoadEnv/ParseSpec.hs view
@@ -0,0 +1,113 @@+module LoadEnv.ParseSpec+ ( spec+ ) where++import LoadEnv.Parse+import Test.Hspec+import Text.Parsec (parse)++spec :: Spec+spec = do+ describe "parseEnvironment" $ do+ it "parses variable declarations among comments and blank lines" $ do+ let env = unlines+ [ "# An environment file"+ , "FOO=bar"+ , "BAZ=\"bat\""+ , "BAT=\"multi-"+ , "pass"+ , "\""+ , ""+ , "# vim ft:sh:"+ ]++ parse parseEnvironment "" env `shouldBe` Right+ [ ("FOO", "bar")+ , ("BAZ", "bat")+ , ("BAT", "multi-\npass\n")+ ]++ it "parses an empty file into an empty list of variables" $ do+ parse parseEnvironment "" "" `shouldBe` Right []+++ describe "parseVariable" $ do+ it "reads unquoted variables" $+ parse parseVariable "" "FOO=bar\n" `shouldBe` Right ("FOO", "bar")++ it "reads quoted variables" $ do+ parse parseVariable "" "FOO=\"bar\"\n"+ `shouldBe` Right ("FOO", "bar")+ parse parseVariable "" "FOO='bar'\n"+ `shouldBe` Right ("FOO", "bar")++ it "allows newlines in quoted variables" $ do+ parse parseVariable "" "FOO=\"foo\nbar\"\n"+ `shouldBe` Right ("FOO", "foo\nbar")++ it "handles empty values" $+ parse parseVariable "" "FOO=\n" `shouldBe` Right ("FOO", "")++ it "handles empty quoted values" $ do+ parse parseVariable "" "FOO=\"\"\n" `shouldBe` Right ("FOO", "")+ parse parseVariable "" "FOO=''\n" `shouldBe` Right ("FOO", "")++ it "handles underscored variables" $+ parse parseVariable "" "FOO_BAR=baz\n"+ `shouldBe` Right ("FOO_BAR", "baz")++ it "treats leading spaces as invalid" $+ parse parseVariable "" " FOO=bar\n"+ `shouldContainError` "unexpected \"F\""++ it "treats spaces around equals as invalid" $+ parse parseVariable "" "FOO = bar\n"+ `shouldContainError` "unexpected \" \""++ it "treats unquoted spaces as invalid" $+ parse parseVariable "" "FOO=bar baz\n"+ `shouldContainError` "unexpected \"b\""++ it "treats unbalanced quotes as invalid" $ do+ parse parseVariable "" "FOO=\"bar\n"+ `shouldContainError` "unexpected end of input"+ parse parseVariable "" "FOO='bar\n"+ `shouldContainError` "unexpected end of input"+ parse parseVariable "" "FOO=bar\"\n"+ `shouldContainError` "unexpected \"\\\"\""+ parse parseVariable "" "FOO=bar'\n"+ `shouldContainError` "unexpected \"\'\""++ it "handles escaped quotes" $ do+ parse parseVariable "" "FOO=\"bar\\\"baz\"\n"+ `shouldBe` Right ("FOO", "bar\"baz")+ parse parseVariable "" "FOO='bar\\'baz'\n"+ `shouldBe` Right ("FOO", "bar'baz")++ it "handles escaped spaces" $+ parse parseVariable "" "FOO=bar\\ baz\n"+ `shouldBe` Right ("FOO", "bar baz")++ it "discards any lines using `export'" $+ parse parseVariable "" "export FOO=bar\n"+ `shouldBe` Right ("FOO", "bar")++ it "requires valid environment variable identifies" $ do+ parse parseVariable "" "S3_KEY=abc123\n"+ `shouldBe` Right ("S3_KEY", "abc123")+ parse parseVariable "" "_S3_KEY=abc123\n"+ `shouldBe` Right ("_S3_KEY", "abc123")++ parse parseVariable "" "S3~KEY=abc123\n"+ `shouldContainError` "unexpected \"~\""+ parse parseVariable "" "S3-KEY=abc123\n"+ `shouldContainError` "unexpected \"-\""+ parse parseVariable "" "S3_key=abc123\n"+ `shouldContainError` "unexpected \"k\""+ parse parseVariable "" "3_KEY=abc123\n"+ `shouldContainError` "unexpected \"3\""++shouldContainError :: Show a => Either a b -> String -> Expectation+v `shouldContainError` msg = either+ (\e -> show e `shouldContain` msg)+ (\_ -> expectationFailure "Expected no parse") v
+ test/LoadEnvSpec.hs view
@@ -0,0 +1,38 @@+module LoadEnvSpec+ ( spec+ ) where++import Control.Monad (when)+import LoadEnv+import System.Directory (doesFileExist, removeFile)+import System.Environment (lookupEnv)+import Test.Hspec++spec :: Spec+spec = after_ cleanup $+ describe "loadEnv" $ do+ it "loads environment variables from ./.env if present" $ do+ writeFile envFile $ unlines+ [ "FOO=\"bar\""+ , "BAZ=\"bat\""+ ]++ loadEnvFrom envFile++ mbar <- lookupEnv "FOO"+ mbat <- lookupEnv "BAZ"+ mbar `shouldBe` Just "bar"+ mbat `shouldBe` Just "bat"++ it "does not fail if the file is not present" $ do+ loadEnvFrom "i-do-not-exist"++ return ()++cleanup :: IO ()+cleanup = do+ e <- doesFileExist envFile+ when e $ removeFile envFile++envFile :: FilePath+envFile = "/tmp/load-env-test-file"