dotenv 2.0.0.beta → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +11 -1
- data/bin/dotenv +1 -1
- data/lib/dotenv.rb +20 -14
- data/lib/dotenv/cli.rb +18 -13
- data/lib/dotenv/environment.rb +4 -2
- data/lib/dotenv/parser.rb +55 -30
- data/lib/dotenv/substitutions/command.rb +9 -7
- data/lib/dotenv/substitutions/variable.rb +2 -5
- data/lib/dotenv/tasks.rb +3 -3
- data/lib/dotenv/version.rb +1 -1
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ccf9d3a79db7a52a63cb5aeca87cec81e21e3ec
|
4
|
+
data.tar.gz: abb6bc7fad7f6b2e2c300ff6b6141f30ccb0bc37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d48b1e23d0ddfac1d8342f97fe4ae862aa43316617561a0d1f702663af6d9ee21716cdef113570a263301422a2e474a572b24992b9fba2114ca3615af6768ab6
|
7
|
+
data.tar.gz: b2c31269eb2977d37b0707759ad1e03ba428a7ed8a46927ec4b2fa2e23a3f8ba8302c5bc03d46a590f5489b413f24d506c2381b76e6c594364f2eb86199b27dd
|
data/README.md
CHANGED
@@ -101,9 +101,19 @@ Whenever your application loads, these variables will be available in `ENV`:
|
|
101
101
|
config.fog_directory = ENV['S3_BUCKET']
|
102
102
|
```
|
103
103
|
|
104
|
+
Comments may be added to your file as such:
|
105
|
+
|
106
|
+
```shell
|
107
|
+
# This is a comment
|
108
|
+
SECRET_KEY=YOURSECRETKEYGOESHERE # comment
|
109
|
+
SECRET_HASH="something-with-a-#-hash"
|
110
|
+
```
|
111
|
+
|
112
|
+
Variable names may not contain the `#` symbol. Values can use the `#` if they are enclosed in quotes.
|
113
|
+
|
104
114
|
## Multiple Rails Environments
|
105
115
|
|
106
|
-
dotenv was originally created to load configuration variables into `ENV` in *development*. There are typically better ways to manage configuration in production environments
|
116
|
+
dotenv was originally created to load configuration variables into `ENV` in *development*. There are typically better ways to manage configuration in production environments - such as `/etc/environment` managed by [Puppet](https://github.com/puppetlabs/puppet) or [Chef](https://github.com/opscode/chef), `heroku config`, etc.
|
107
117
|
|
108
118
|
However, some find dotenv to be a convenient way to configure Rails applications in staging and production environments, and you can do that by defining environment-specific files like `.env.production` or `.env.test`.
|
109
119
|
|
data/bin/dotenv
CHANGED
data/lib/dotenv.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "dotenv/parser"
|
2
|
+
require "dotenv/environment"
|
3
3
|
|
4
|
+
# The top level Dotenv module. The entrypoint for the application logic.
|
4
5
|
module Dotenv
|
5
|
-
|
6
|
+
class << self
|
7
|
+
attr_accessor :instrumenter
|
8
|
+
end
|
6
9
|
|
7
|
-
|
10
|
+
module_function
|
8
11
|
|
9
12
|
def load(*filenames)
|
10
13
|
with(*filenames) do |f|
|
11
|
-
|
14
|
+
ignoring_nonexistent_files do
|
12
15
|
env = Environment.new(f)
|
13
|
-
instrument(
|
16
|
+
instrument("dotenv.load", :env => env) { env.apply }
|
14
17
|
end
|
15
18
|
end
|
16
19
|
end
|
@@ -19,16 +22,16 @@ module Dotenv
|
|
19
22
|
def load!(*filenames)
|
20
23
|
with(*filenames) do |f|
|
21
24
|
env = Environment.new(f)
|
22
|
-
instrument(
|
25
|
+
instrument("dotenv.load", :env => env) { env.apply }
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
26
29
|
# same as `load`, but will override existing values in `ENV`
|
27
30
|
def overload(*filenames)
|
28
31
|
with(*filenames) do |f|
|
29
|
-
|
32
|
+
ignoring_nonexistent_files do
|
30
33
|
env = Environment.new(f)
|
31
|
-
instrument(
|
34
|
+
instrument("dotenv.overload", :env => env) { env.apply! }
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
@@ -37,12 +40,10 @@ module Dotenv
|
|
37
40
|
#
|
38
41
|
# Returns a hash of all the loaded environment variables.
|
39
42
|
def with(*filenames, &block)
|
40
|
-
filenames <<
|
43
|
+
filenames << ".env" if filenames.empty?
|
41
44
|
|
42
|
-
{}
|
43
|
-
|
44
|
-
hash.merge! block.call(File.expand_path(filename)) || {}
|
45
|
-
end
|
45
|
+
filenames.reduce({}) do |hash, filename|
|
46
|
+
hash.merge! block.call(File.expand_path(filename)) || {}
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
@@ -53,4 +54,9 @@ module Dotenv
|
|
53
54
|
block.call
|
54
55
|
end
|
55
56
|
end
|
57
|
+
|
58
|
+
def ignoring_nonexistent_files
|
59
|
+
yield
|
60
|
+
rescue Errno::ENOENT
|
61
|
+
end
|
56
62
|
end
|
data/lib/dotenv/cli.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require "dotenv"
|
2
2
|
|
3
3
|
module Dotenv
|
4
|
+
# The CLI is a class responsible of handling all the command line interface
|
5
|
+
# logic.
|
4
6
|
class CLI
|
5
7
|
attr_reader :argv
|
6
8
|
|
@@ -9,23 +11,26 @@ module Dotenv
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def run
|
12
|
-
filenames =
|
13
|
-
# drop the -f
|
14
|
-
argv.delete_at pos
|
15
|
-
# parse one or more comma-separated .env files
|
16
|
-
require 'csv'
|
17
|
-
CSV.parse_line argv.delete_at(pos)
|
18
|
-
else
|
19
|
-
[]
|
20
|
-
end
|
21
|
-
|
14
|
+
filenames = parse_filenames || []
|
22
15
|
begin
|
23
|
-
Dotenv.load!
|
16
|
+
Dotenv.load!(*filenames)
|
24
17
|
rescue Errno::ENOENT => e
|
25
18
|
abort e.message
|
26
19
|
else
|
27
|
-
exec
|
20
|
+
exec(*argv) unless argv.empty?
|
28
21
|
end
|
29
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def parse_filenames
|
27
|
+
pos = argv.index("-f")
|
28
|
+
return nil unless pos
|
29
|
+
# drop the -f
|
30
|
+
argv.delete_at pos
|
31
|
+
# parse one or more comma-separated .env files
|
32
|
+
require "csv"
|
33
|
+
CSV.parse_line argv.delete_at(pos)
|
34
|
+
end
|
30
35
|
end
|
31
36
|
end
|
data/lib/dotenv/environment.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Dotenv
|
2
|
+
# This class inherits from Hash and represents the environemnt into which
|
3
|
+
# Dotenv will load key value pairs from a file.
|
2
4
|
class Environment < Hash
|
3
5
|
attr_reader :filename
|
4
6
|
|
@@ -16,11 +18,11 @@ module Dotenv
|
|
16
18
|
end
|
17
19
|
|
18
20
|
def apply
|
19
|
-
each { |k,v| ENV[k] ||= v }
|
21
|
+
each { |k, v| ENV[k] ||= v }
|
20
22
|
end
|
21
23
|
|
22
24
|
def apply!
|
23
|
-
each { |k,v| ENV[k] = v }
|
25
|
+
each { |k, v| ENV[k] = v }
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
data/lib/dotenv/parser.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
require
|
2
|
-
if RUBY_VERSION >
|
3
|
-
require 'dotenv/substitutions/command'
|
4
|
-
end
|
1
|
+
require "dotenv/substitutions/variable"
|
2
|
+
require "dotenv/substitutions/command" if RUBY_VERSION > "1.8.7"
|
5
3
|
|
6
4
|
module Dotenv
|
7
5
|
class FormatError < SyntaxError; end
|
8
6
|
|
7
|
+
# This class enables parsing of a string for key value pairs to be returned
|
8
|
+
# and stored in the Environment. It allows for variable substitutions and
|
9
|
+
# exporting of variables.
|
9
10
|
class Parser
|
10
|
-
|
11
|
+
@substitutions =
|
12
|
+
Substitutions.constants.map { |const| Substitutions.const_get(const) }
|
11
13
|
|
12
14
|
LINE = /
|
13
15
|
\A
|
@@ -25,44 +27,67 @@ module Dotenv
|
|
25
27
|
\z
|
26
28
|
/x
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
+
class << self
|
31
|
+
attr_reader :substitutions
|
32
|
+
|
33
|
+
def call(string)
|
34
|
+
new(string).call
|
35
|
+
end
|
30
36
|
end
|
31
37
|
|
32
38
|
def initialize(string)
|
33
39
|
@string = string
|
40
|
+
@hash = {}
|
34
41
|
end
|
35
42
|
|
36
43
|
def call
|
37
|
-
@string.split("\n").
|
38
|
-
|
39
|
-
|
44
|
+
@string.split("\n").each do |line|
|
45
|
+
parse_line(line)
|
46
|
+
end
|
47
|
+
@hash
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
40
51
|
|
41
|
-
|
42
|
-
|
43
|
-
|
52
|
+
def parse_line(line)
|
53
|
+
if (match = line.match(LINE))
|
54
|
+
key, value = match.captures
|
55
|
+
@hash[key] = parse_value(value || "")
|
56
|
+
elsif line.split.first == "export"
|
57
|
+
if variable_not_set?(line)
|
58
|
+
fail FormatError, "Line #{line.inspect} has an unset variable"
|
59
|
+
end
|
60
|
+
elsif line !~ /\A\s*(?:#.*)?\z/ # not comment or blank line
|
61
|
+
fail FormatError, "Line #{line.inspect} doesn't match format"
|
62
|
+
end
|
63
|
+
end
|
44
64
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
value = value.gsub(/\\([^$])/, '\1')
|
49
|
-
end
|
65
|
+
def parse_value(value)
|
66
|
+
# Remove surrounding quotes
|
67
|
+
value = value.strip.sub(/\A(['"])(.*)\1\z/, '\2')
|
50
68
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
69
|
+
if Regexp.last_match(1) == '"'
|
70
|
+
value = unescape_characters(expand_newlines(value))
|
71
|
+
end
|
56
72
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
raise FormatError, "Line #{line.inspect} has a variable that is not set" unless line.split[1..-1].all?{ |var| hash.member?(var) }
|
61
|
-
elsif line !~ /\A\s*(?:#.*)?\z/ # not comment or blank line
|
62
|
-
raise FormatError, "Line #{line.inspect} doesn't match format"
|
73
|
+
if Regexp.last_match(1) != "'"
|
74
|
+
self.class.substitutions.each do |proc|
|
75
|
+
value = proc.call(value, @hash)
|
63
76
|
end
|
64
|
-
hash
|
65
77
|
end
|
78
|
+
value
|
79
|
+
end
|
80
|
+
|
81
|
+
def unescape_characters(value)
|
82
|
+
value.gsub(/\\([^$])/, '\1')
|
83
|
+
end
|
84
|
+
|
85
|
+
def expand_newlines(value)
|
86
|
+
value.gsub('\n', "\n")
|
87
|
+
end
|
88
|
+
|
89
|
+
def variable_not_set?(line)
|
90
|
+
!line.split[1..-1].all? { |var| @hash.member?(var) }
|
66
91
|
end
|
67
92
|
end
|
68
93
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "English"
|
2
|
+
|
1
3
|
module Dotenv
|
2
4
|
module Substitutions
|
3
5
|
# Substitute shell commands in a value.
|
@@ -6,26 +8,27 @@ module Dotenv
|
|
6
8
|
#
|
7
9
|
module Command
|
8
10
|
class << self
|
9
|
-
|
10
11
|
INTERPOLATED_SHELL_COMMAND = /
|
11
12
|
(?<backslash>\\)? # is it escaped with a backslash?
|
12
13
|
\$ # literal $
|
13
14
|
(?<cmd> # collect command content for eval
|
14
15
|
\( # require opening paren
|
15
|
-
([^()]|\g<cmd>)+ # allow any number of non-parens, or balanced
|
16
|
+
([^()]|\g<cmd>)+ # allow any number of non-parens, or balanced
|
17
|
+
# parens (by nesting the <cmd> expression
|
18
|
+
# recursively)
|
16
19
|
\) # require closing paren
|
17
20
|
)
|
18
21
|
/x
|
19
22
|
|
20
|
-
def call(value,
|
23
|
+
def call(value, _env)
|
21
24
|
# Process interpolated shell commands
|
22
25
|
value.gsub(INTERPOLATED_SHELL_COMMAND) do |*|
|
23
26
|
# Eliminate opening and closing parentheses
|
24
|
-
command =
|
27
|
+
command = $LAST_MATCH_INFO[:cmd][1..-2]
|
25
28
|
|
26
|
-
if
|
29
|
+
if $LAST_MATCH_INFO[:backslash]
|
27
30
|
# Command is escaped, don't replace it.
|
28
|
-
|
31
|
+
$LAST_MATCH_INFO[0][1..-1]
|
29
32
|
else
|
30
33
|
# Execute the command and return the value
|
31
34
|
`#{command}`.chomp
|
@@ -33,7 +36,6 @@ module Dotenv
|
|
33
36
|
end
|
34
37
|
end
|
35
38
|
end
|
36
|
-
|
37
39
|
end
|
38
40
|
end
|
39
41
|
end
|
@@ -7,7 +7,6 @@ module Dotenv
|
|
7
7
|
#
|
8
8
|
module Variable
|
9
9
|
class << self
|
10
|
-
|
11
10
|
VARIABLE = /
|
12
11
|
(\\)? # is it escaped with a backslash?
|
13
12
|
(\$) # literal $
|
@@ -23,20 +22,18 @@ module Dotenv
|
|
23
22
|
value.scan(VARIABLE).each do |parts|
|
24
23
|
if parts.first == '\\'
|
25
24
|
# Variable is escaped, don't replace it.
|
26
|
-
replace = parts[1...-1].join(
|
25
|
+
replace = parts[1...-1].join("")
|
27
26
|
else
|
28
27
|
# Replace it with the value from the environment
|
29
28
|
replace = env.fetch(parts.last) { ENV[parts.last] }
|
30
29
|
end
|
31
30
|
|
32
|
-
value = value.sub(parts[0...-1].join(
|
31
|
+
value = value.sub(parts[0...-1].join(""), replace || "")
|
33
32
|
end
|
34
33
|
|
35
34
|
value
|
36
35
|
end
|
37
36
|
end
|
38
|
-
|
39
37
|
end
|
40
|
-
|
41
38
|
end
|
42
39
|
end
|
data/lib/dotenv/tasks.rb
CHANGED
data/lib/dotenv/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dotenv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Keepers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: Loads environment variables from `.env`.
|
42
56
|
email:
|
43
57
|
- brandon@opensoul.org
|
@@ -72,9 +86,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
72
86
|
version: '0'
|
73
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
88
|
requirements:
|
75
|
-
- - "
|
89
|
+
- - ">="
|
76
90
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
91
|
+
version: '0'
|
78
92
|
requirements: []
|
79
93
|
rubyforge_project:
|
80
94
|
rubygems_version: 2.2.2
|