dotenv 0.5.0.2 → 0.5.1.0
raw patch · 8 files changed
+71/−6 lines, 8 filesdep ~processPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: process
API changes (from Hackage documentation)
+ Configuration.Dotenv.ParsedVariable: CommandInterpolation :: String -> VarFragment
Files
- CHANGELOG.md +4/−0
- README.md +32/−0
- dotenv.cabal +4/−2
- spec/Configuration/Dotenv/ParseSpec.hs +6/−0
- spec/Configuration/DotenvSpec.hs +6/−0
- spec/fixtures/.dotenv +1/−0
- src/Configuration/Dotenv/Parse.hs +13/−3
- src/Configuration/Dotenv/ParsedVariable.hs +5/−1
CHANGELOG.md view
@@ -1,4 +1,8 @@ ## MASTER+## Dotenv 0.5.1.0++* Add support for command substitution on env vars.+ ## Dotenv 0.5.0.2 * Set `.env` file as default file for environment variables.
README.md view
@@ -59,6 +59,38 @@ about this. Fortunately, there is already some work for this issue in [GHC Phabricator](https://phabricator.haskell.org/D3726). +### Variable substitution++In order to use compound env vars use the following sintax within your env vars+${your_env_var}. For instance:++```+DATABASE=postgres://${USER}@localhost/database+```+ +Running it on the CLI:++```+$ dotenv "echo $DATABASE"+postgres://myusername@localhost/database+```++### Command substitution++In order to use the standard output of a command in your env vars use the following+sintax $(your_command). For instance:++```+DATABASE=postgres://$(whoami)@localhost/database+```+ +Running it on the CLI:++```+$ dotenv "echo $DATABASE"+postgres://myusername@localhost/database+```+ ## Configuration The first argument to `loadFile` specifies whether you want to
dotenv.cabal view
@@ -1,5 +1,5 @@ name: dotenv-version: 0.5.0.2+version: 0.5.1.0 synopsis: Loads environment variables from dotenv files homepage: https://github.com/stackbuilders/dotenv-hs description:@@ -61,7 +61,7 @@ , dotenv , optparse-applicative >=0.11 && < 0.15 , megaparsec >= 6.0 && < 7.0- , process+ , process >= 1.4.3.0 , text , transformers >=0.4 && < 0.6 other-modules: Paths_dotenv@@ -83,6 +83,7 @@ build-depends: base >=4.7 && <5.0 , base-compat >= 0.4 , megaparsec >= 6.0 && < 7.0+ , process >= 1.4.3.0 , text , transformers >=0.4 && < 0.6 , exceptions >= 0.8 && < 0.9@@ -116,6 +117,7 @@ , dotenv , megaparsec >= 6.0 && < 7.0 , hspec+ , process >= 1.4.3.0 , text , transformers >=0.4 && < 0.6 , exceptions >= 0.8 && < 0.9
spec/Configuration/Dotenv/ParseSpec.hs view
@@ -142,5 +142,11 @@ it "doesn't allow more configuration options after a quoted value" $ parseConfig `shouldFailOn` "foo='bar'baz='buz'" + it "parses a command $(command)" $ do+ parseConfig "FOO=$(command)"+ `shouldParse` [ParsedVariable "FOO" (Unquoted [CommandInterpolation "command"])]+ parseConfig "FOO=asdf_$(command)"+ `shouldParse` [ParsedVariable "FOO" (Unquoted [VarLiteral "asdf_", CommandInterpolation "command"])]+ parseConfig :: String -> Either (ParseError Char Void) [ParsedVariable] parseConfig = parse configParser ""
spec/Configuration/DotenvSpec.hs view
@@ -7,6 +7,7 @@ import Test.Hspec +import System.Process (readCreateProcess, shell) import System.Environment (lookupEnv) import Control.Monad (liftM) import Data.Maybe (fromMaybe)@@ -111,6 +112,11 @@ it "recognises previous variables" $ liftM (!! 3) (parseFile "spec/fixtures/.dotenv") `shouldReturn` ("PREVIOUS", "true")++ it "recognises commands" $ do+ me <- init <$> readCreateProcess (shell "whoami") ""+ liftM (!! 4) (parseFile "spec/fixtures/.dotenv") `shouldReturn`+ ("ME", me) describe "onMissingFile" $ after_ (unsetEnv "DOTENV") $ do context "when target file is present" $
spec/fixtures/.dotenv view
@@ -2,3 +2,4 @@ UNICODE_TEST=Manabí ENVIRONMENT="$HOME" PREVIOUS="$DOTENV"+ME="$(whoami)"
src/Configuration/Dotenv/Parse.hs view
@@ -60,14 +60,24 @@ quotedWith DoubleQuote = DoubleQuoted <$> (between (char '\"') (char '\"') $ many (fragment "\"")) fragment :: [Char] -> Parser VarFragment-fragment charsToEscape = interpolatedValueFragment <|> literalValueFragment ('$' : '\\' : charsToEscape)+fragment charsToEscape =+ interpolatedValueCommandInterpolation+ <|> interpolatedValueVarInterpolation+ <|> literalValueFragment ('$' : '\\' : charsToEscape) -interpolatedValueFragment :: Parser VarFragment-interpolatedValueFragment = VarInterpolation <$>+interpolatedValueVarInterpolation :: Parser VarFragment+interpolatedValueVarInterpolation = VarInterpolation <$> ((between (symbol "${") (symbol "}") variableName) <|> (char '$' >> variableName)) where symbol = L.symbol sc++interpolatedValueCommandInterpolation :: Parser VarFragment+interpolatedValueCommandInterpolation =+ CommandInterpolation+ <$> between (symbol "$(") (symbol ")") (many alphaNumChar)+ where+ symbol = L.symbol sc literalValueFragment :: [Char] -> Parser VarFragment literalValueFragment charsToEscape = VarLiteral <$> (some $ escapedChar <|> normalChar)
src/Configuration/Dotenv/ParsedVariable.hs view
@@ -13,6 +13,7 @@ #endif import Control.Applicative ((<|>)) import System.Environment (lookupEnv)+import System.Process (readCreateProcess, shell) data ParsedVariable = ParsedVariable VarName VarValue deriving (Show, Eq)@@ -28,7 +29,8 @@ data VarFragment = VarInterpolation String- | VarLiteral String deriving (Show, Eq)+ | VarLiteral String+ | CommandInterpolation String deriving (Show, Eq) interpolateParsedVariables :: [ParsedVariable] -> IO [(String, String)] interpolateParsedVariables = fmap reverse . foldM addInterpolated []@@ -49,9 +51,11 @@ interpolateFragment previous (VarInterpolation varname) = fromPreviousOrEnv >>= maybe (return "") return where fromPreviousOrEnv = (lookup varname previous <|>) <$> lookupEnv varname+interpolateFragment _ (CommandInterpolation commandName) = init <$> readCreateProcess (shell commandName) "" joinContents :: VarContents -> String joinContents = concatMap fragmentToString where+ fragmentToString (CommandInterpolation value) = value fragmentToString (VarInterpolation value) = value fragmentToString (VarLiteral value) = value