Skip to content

Commit

Permalink
Merge branch 'master' into variable_precedence
Browse files Browse the repository at this point in the history
  • Loading branch information
cbjoseph authored Apr 17, 2018
2 parents 7f82f73 + 3b096d2 commit 9b5d46a
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 21 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
language: ruby

rvm:
- 2.5.0
- 2.4.1
- 2.3.4
- 2.2.7
Expand Down
10 changes: 8 additions & 2 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# Changelog

[Unreleased changes](https://github.com/bkeepers/dotenv/compare/v2.2.1...master)
[Unreleased changes](https://github.com/bkeepers/dotenv/compare/v2.2.2...master)

## 2.2.2 - Apr 9, 2018

* Support Rails 5.2 ([#325](https://github.com/bkeepers/dotenv/pull/325))

[Full Changelog](https://github.com/bkeepers/dotenv/compare/v2.2.1...v2.2.2)

## 2.2.1 - Apr 28, 2017

* Support Rails 5.1 ([#599](https://github.com/bkeepers/dotenv/pull/299))
* Support Rails 5.1 ([#299](https://github.com/bkeepers/dotenv/pull/299))

[Full Changelog](https://github.com/bkeepers/dotenv/compare/v2.2.0...v2.2.1)

Expand Down
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ Alternatively, you can use the `dotenv` executable to launch your application:
$ dotenv ./script.rb
```

The `dotenv` executable also accepts a single flag, `-f`. Its value should be a comma-separated list of configuration files, in the order of most important to least. All of the files must exist. There _must_ be a space between the flag and its value.

```
$ dotenv -f ".env.local,.env" ./script.rb
```

To ensure `.env` is loaded in rake, load the tasks:

```ruby
Expand Down Expand Up @@ -112,9 +118,21 @@ export SECRET_KEY=YOURSECRETKEYGOESHERE
If you need multiline variables, for example private keys, you can double quote strings and use the `\n` character for newlines:

```shell
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nHkVN9\n-----END DSA PRIVATE KEY-----\n"
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nHkVN9...\n-----END DSA PRIVATE KEY-----\n"
```

Alternatively, multi-line values with line breaks are now supported for quoted values.

```shell
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
...
HkVN9...
...
-----END DSA PRIVATE KEY-----"
```

This is particularly helpful when using the Heroku command line plugin [`heroku-config`](https://github.com/xavdid/heroku-config) to pull configuration variables down that may have line breaks.

### Command Substitution

You need to add the output of a command in one of your variables? Simply add it with `$(your_command)`:
Expand Down
2 changes: 1 addition & 1 deletion dotenv-rails.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Gem::Specification.new "dotenv-rails", Dotenv::VERSION do |gem|
) + ["README.md", "LICENSE"]

gem.add_dependency "dotenv", Dotenv::VERSION
gem.add_dependency "railties", ">= 3.2", "< 5.2"
gem.add_dependency "railties", ">= 3.2", "< 6.0"

gem.add_development_dependency "spring"
end
24 changes: 11 additions & 13 deletions lib/dotenv/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,19 @@ class Parser
[Dotenv::Substitutions::Variable, Dotenv::Substitutions::Command]

LINE = /
\A
\s*
(?:export\s+)? # optional export
([\w\.]+) # key
(?:\s*=\s*|:\s+?) # separator
( # optional value begin
'(?:\'|[^'])*' # single quoted value
'(?:\\'|[^'])*' # single quoted value
| # or
"(?:\"|[^"])*" # double quoted value
"(?:\\"|[^"])*" # double quoted value
| # or
[^#\n]+ # unquoted value
[^#\r\n]+ # unquoted value
)? # value end
\s*
(?:\#.*)? # optional comment
\z
/x

class << self
Expand All @@ -44,7 +42,12 @@ def initialize(string, is_load)
end

def call
@string.split(/[\n\r]+/).each do |line|
# Process matches
@string.scan(LINE).each do |key, value|
@hash[key] = parse_value(value || "")
end
# Process non-matches
@string.gsub(LINE, "").split(/[\n\r]+/).each do |line|
parse_line(line)
end
@hash
Expand All @@ -53,21 +56,16 @@ def call
private

def parse_line(line)
if (match = line.match(LINE))
key, value = match.captures
@hash[key] = parse_value(value || "")
elsif line.split.first == "export"
if line.split.first == "export"
if variable_not_set?(line)
raise FormatError, "Line #{line.inspect} has an unset variable"
end
elsif line !~ /\A\s*(?:#.*)?\z/ # not comment or blank line
raise FormatError, "Line #{line.inspect} doesn't match format"
end
end

def parse_value(value)
# Remove surrounding quotes
value = value.strip.sub(/\A(['"])(.*)\1\z/, '\2')
value = value.strip.sub(/\A(['"])(.*)\1\z/m, '\2')

if Regexp.last_match(1) == '"'
value = unescape_characters(expand_newlines(value))
Expand Down
2 changes: 1 addition & 1 deletion lib/dotenv/rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
event = ActiveSupport::Notifications::Event.new(*args)
Spring.watch event.payload[:env].filename if Rails.application
end
rescue LoadError
rescue LoadError, ArgumentError
# Spring is not available
end

Expand Down
1 change: 1 addition & 0 deletions lib/dotenv/substitutions/variable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def substitute(match, variable, env)
variable
end
end

end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/dotenv/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Dotenv
VERSION = "2.2.1".freeze
VERSION = "2.2.2".freeze
end
42 changes: 40 additions & 2 deletions spec/dotenv/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ def env(string)
expect(env("foo=bar ")).to eql("foo" => "bar") # not 'bar '
end

it "throws an error if line format is incorrect" do
expect { env("lol$wut") }.to raise_error(Dotenv::FormatError)
it "ignores lines that are not variable assignments" do
expect(env("lol$wut")).to eql({})
end

it "ignores empty lines" do
Expand Down Expand Up @@ -161,6 +161,44 @@ def env(string)
expect(env("foo=")).to eql("foo" => "")
end

it "allows multi-line values in single quotes" do
env_file = %(OPTION_A=first line
export OPTION_B='line 1
line 2
line 3'
OPTION_C="last line"
OPTION_ESCAPED='line one
this is \\'quoted\\'
one more line')

expected_result = {
"OPTION_A" => "first line",
"OPTION_B" => "line 1\nline 2\nline 3",
"OPTION_C" => "last line",
"OPTION_ESCAPED" => "line one\nthis is \\'quoted\\'\none more line"
}
expect(env(env_file)).to eql(expected_result)
end

it "allows multi-line values in double quotes" do
env_file = %(OPTION_A=first line
export OPTION_B="line 1
line 2
line 3"
OPTION_C="last line"
OPTION_ESCAPED="line one
this is \\"quoted\\"
one more line")

expected_result = {
"OPTION_A" => "first line",
"OPTION_B" => "line 1\nline 2\nline 3",
"OPTION_C" => "last line",
"OPTION_ESCAPED" => "line one\nthis is \"quoted\"\none more line"
}
expect(env(env_file)).to eql(expected_result)
end

if RUBY_VERSION > "1.8.7"
it "parses shell commands interpolated in $()" do
expect(env("echo=$(echo hello)")).to eql("echo" => "hello")
Expand Down

0 comments on commit 9b5d46a

Please sign in to comment.