dotenv 2.0.0.beta → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|