dotenv 0.9.0 → 2.7.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +187 -24
- data/bin/dotenv +2 -10
- data/lib/dotenv.rb +75 -14
- data/lib/dotenv/cli.rb +80 -0
- data/lib/dotenv/environment.rb +13 -61
- data/lib/dotenv/load.rb +2 -0
- data/lib/dotenv/missing_keys.rb +10 -0
- data/lib/dotenv/parser.rb +98 -0
- data/lib/dotenv/substitutions/command.rb +41 -0
- data/lib/dotenv/substitutions/variable.rb +47 -0
- data/lib/dotenv/tasks.rb +3 -3
- data/lib/dotenv/template.rb +21 -0
- data/lib/dotenv/version.rb +1 -1
- metadata +35 -48
- data/.env +0 -1
- data/.gitignore +0 -8
- data/.travis.yml +0 -6
- data/Changelog.md +0 -83
- data/Gemfile +0 -6
- data/Guardfile +0 -9
- data/Rakefile +0 -30
- data/dotenv-rails.gemspec +0 -17
- data/dotenv.gemspec +0 -20
- data/lib/dotenv-rails.rb +0 -1
- data/lib/dotenv/capistrano.rb +0 -5
- data/lib/dotenv/capistrano/recipes.rb +0 -10
- data/lib/dotenv/format_error.rb +0 -4
- data/lib/dotenv/railtie.rb +0 -14
- data/spec/dotenv/environment_spec.rb +0 -137
- data/spec/dotenv_spec.rb +0 -92
- data/spec/fixtures/exported.env +0 -2
- data/spec/fixtures/plain.env +0 -5
- data/spec/fixtures/quoted.env +0 -8
- data/spec/fixtures/yaml.env +0 -4
- data/spec/spec_helper.rb +0 -7
data/lib/dotenv/environment.rb
CHANGED
@@ -1,76 +1,28 @@
|
|
1
|
-
require 'dotenv/format_error'
|
2
|
-
|
3
1
|
module Dotenv
|
2
|
+
# This class inherits from Hash and represents the environment into which
|
3
|
+
# Dotenv will load key value pairs from a file.
|
4
4
|
class Environment < Hash
|
5
|
-
|
6
|
-
\A
|
7
|
-
(?:export\s+)? # optional export
|
8
|
-
([\w\.]+) # key
|
9
|
-
(?:\s*=\s*|:\s+?) # separator
|
10
|
-
( # optional value begin
|
11
|
-
'(?:\'|[^'])*' # single quoted value
|
12
|
-
| # or
|
13
|
-
"(?:\"|[^"])*" # double quoted value
|
14
|
-
| # or
|
15
|
-
[^#\n]+ # unquoted value
|
16
|
-
)? # value end
|
17
|
-
(?:\s*\#.*)? # optional comment
|
18
|
-
\z
|
19
|
-
/x
|
20
|
-
VARIABLE = /
|
21
|
-
(\\)?
|
22
|
-
(\$)
|
23
|
-
( # collect braces with var for sub
|
24
|
-
\{? # allow brace wrapping
|
25
|
-
([A-Z0-9_]+) # match the variable
|
26
|
-
\}? # closing brace
|
27
|
-
)
|
28
|
-
/xi
|
5
|
+
attr_reader :filename
|
29
6
|
|
30
|
-
def initialize(filename)
|
7
|
+
def initialize(filename, is_load = false)
|
31
8
|
@filename = filename
|
32
|
-
load
|
9
|
+
load(is_load)
|
33
10
|
end
|
34
11
|
|
35
|
-
def load
|
36
|
-
read
|
37
|
-
if match = line.match(LINE)
|
38
|
-
key, value = match.captures
|
39
|
-
|
40
|
-
value ||= ''
|
41
|
-
# Remove surrounding quotes
|
42
|
-
value = value.strip.sub(/\A(['"])(.*)\1\z/, '\2')
|
43
|
-
|
44
|
-
if $1 == '"'
|
45
|
-
value = value.gsub('\n', "\n")
|
46
|
-
# Unescape all characters except $ so variables can be escaped properly
|
47
|
-
value = value.gsub(/\\([^$])/, '\1')
|
48
|
-
end
|
49
|
-
|
50
|
-
# Process embedded variables
|
51
|
-
value.scan(VARIABLE).each do |parts|
|
52
|
-
if parts.first == '\\'
|
53
|
-
replace = parts[1...-1].join('')
|
54
|
-
else
|
55
|
-
replace = self.fetch(parts.last) { ENV[parts.last] }
|
56
|
-
end
|
57
|
-
|
58
|
-
value = value.sub(parts[0...-1].join(''), replace || '')
|
59
|
-
end
|
60
|
-
|
61
|
-
self[key] = value
|
62
|
-
elsif line !~ /\A\s*(?:#.*)?\z/ # not comment or blank line
|
63
|
-
raise FormatError, "Line #{line.inspect} doesn't match format"
|
64
|
-
end
|
65
|
-
end
|
12
|
+
def load(is_load = false)
|
13
|
+
update Parser.call(read, is_load)
|
66
14
|
end
|
67
15
|
|
68
16
|
def read
|
69
|
-
File.
|
17
|
+
File.open(@filename, "rb:bom|utf-8", &:read)
|
70
18
|
end
|
71
19
|
|
72
20
|
def apply
|
73
|
-
each { |k,v| ENV[k] ||= v }
|
21
|
+
each { |k, v| ENV[k] ||= v }
|
22
|
+
end
|
23
|
+
|
24
|
+
def apply!
|
25
|
+
each { |k, v| ENV[k] = v }
|
74
26
|
end
|
75
27
|
end
|
76
28
|
end
|
data/lib/dotenv/load.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require "dotenv/substitutions/variable"
|
2
|
+
require "dotenv/substitutions/command" if RUBY_VERSION > "1.8.7"
|
3
|
+
|
4
|
+
module Dotenv
|
5
|
+
class FormatError < SyntaxError; end
|
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.
|
10
|
+
class Parser
|
11
|
+
@substitutions =
|
12
|
+
[Dotenv::Substitutions::Variable, Dotenv::Substitutions::Command]
|
13
|
+
|
14
|
+
LINE = /
|
15
|
+
(?:^|\A) # beginning of line
|
16
|
+
\s* # leading whitespace
|
17
|
+
(?:export\s+)? # optional export
|
18
|
+
([\w\.]+) # key
|
19
|
+
(?:\s*=\s*?|:\s+?) # separator
|
20
|
+
( # optional value begin
|
21
|
+
\s*'(?:\\'|[^'])*' # single quoted value
|
22
|
+
| # or
|
23
|
+
\s*"(?:\\"|[^"])*" # double quoted value
|
24
|
+
| # or
|
25
|
+
[^\#\r\n]+ # unquoted value
|
26
|
+
)? # value end
|
27
|
+
\s* # trailing whitespace
|
28
|
+
(?:\#.*)? # optional comment
|
29
|
+
(?:$|\z) # end of line
|
30
|
+
/x
|
31
|
+
|
32
|
+
class << self
|
33
|
+
attr_reader :substitutions
|
34
|
+
|
35
|
+
def call(string, is_load = false)
|
36
|
+
new(string, is_load).call
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(string, is_load = false)
|
41
|
+
@string = string
|
42
|
+
@hash = {}
|
43
|
+
@is_load = is_load
|
44
|
+
end
|
45
|
+
|
46
|
+
def call
|
47
|
+
# Convert line breaks to same format
|
48
|
+
lines = @string.gsub(/\r\n?/, "\n")
|
49
|
+
# Process matches
|
50
|
+
lines.scan(LINE).each do |key, value|
|
51
|
+
@hash[key] = parse_value(value || "")
|
52
|
+
end
|
53
|
+
# Process non-matches
|
54
|
+
lines.gsub(LINE, "").split(/[\n\r]+/).each do |line|
|
55
|
+
parse_line(line)
|
56
|
+
end
|
57
|
+
@hash
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def parse_line(line)
|
63
|
+
if line.split.first == "export"
|
64
|
+
if variable_not_set?(line)
|
65
|
+
raise FormatError, "Line #{line.inspect} has an unset variable"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def parse_value(value)
|
71
|
+
# Remove surrounding quotes
|
72
|
+
value = value.strip.sub(/\A(['"])(.*)\1\z/m, '\2')
|
73
|
+
|
74
|
+
if Regexp.last_match(1) == '"'
|
75
|
+
value = unescape_characters(expand_newlines(value))
|
76
|
+
end
|
77
|
+
|
78
|
+
if Regexp.last_match(1) != "'"
|
79
|
+
self.class.substitutions.each do |proc|
|
80
|
+
value = proc.call(value, @hash, @is_load)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
value
|
84
|
+
end
|
85
|
+
|
86
|
+
def unescape_characters(value)
|
87
|
+
value.gsub(/\\([^$])/, '\1')
|
88
|
+
end
|
89
|
+
|
90
|
+
def expand_newlines(value)
|
91
|
+
value.gsub('\n', "\n").gsub('\r', "\r")
|
92
|
+
end
|
93
|
+
|
94
|
+
def variable_not_set?(line)
|
95
|
+
!line.split[1..-1].all? { |var| @hash.member?(var) }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "English"
|
2
|
+
|
3
|
+
module Dotenv
|
4
|
+
module Substitutions
|
5
|
+
# Substitute shell commands in a value.
|
6
|
+
#
|
7
|
+
# SHA=$(git rev-parse HEAD)
|
8
|
+
#
|
9
|
+
module Command
|
10
|
+
class << self
|
11
|
+
INTERPOLATED_SHELL_COMMAND = /
|
12
|
+
(?<backslash>\\)? # is it escaped with a backslash?
|
13
|
+
\$ # literal $
|
14
|
+
(?<cmd> # collect command content for eval
|
15
|
+
\( # require opening paren
|
16
|
+
([^()]|\g<cmd>)+ # allow any number of non-parens, or balanced
|
17
|
+
# parens (by nesting the <cmd> expression
|
18
|
+
# recursively)
|
19
|
+
\) # require closing paren
|
20
|
+
)
|
21
|
+
/x
|
22
|
+
|
23
|
+
def call(value, _env, _is_load)
|
24
|
+
# Process interpolated shell commands
|
25
|
+
value.gsub(INTERPOLATED_SHELL_COMMAND) do |*|
|
26
|
+
# Eliminate opening and closing parentheses
|
27
|
+
command = $LAST_MATCH_INFO[:cmd][1..-2]
|
28
|
+
|
29
|
+
if $LAST_MATCH_INFO[:backslash]
|
30
|
+
# Command is escaped, don't replace it.
|
31
|
+
$LAST_MATCH_INFO[0][1..-1]
|
32
|
+
else
|
33
|
+
# Execute the command and return the value
|
34
|
+
`#{command}`.chomp
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "English"
|
2
|
+
|
3
|
+
module Dotenv
|
4
|
+
module Substitutions
|
5
|
+
# Substitute variables in a value.
|
6
|
+
#
|
7
|
+
# HOST=example.com
|
8
|
+
# URL="https://$HOST"
|
9
|
+
#
|
10
|
+
module Variable
|
11
|
+
class << self
|
12
|
+
VARIABLE = /
|
13
|
+
(\\)? # is it escaped with a backslash?
|
14
|
+
(\$) # literal $
|
15
|
+
(?!\() # shouldnt be followed by paranthesis
|
16
|
+
\{? # allow brace wrapping
|
17
|
+
([A-Z0-9_]+)? # optional alpha nums
|
18
|
+
\}? # closing brace
|
19
|
+
/xi
|
20
|
+
|
21
|
+
def call(value, env, is_load)
|
22
|
+
combined_env = if is_load
|
23
|
+
env.merge(ENV)
|
24
|
+
else
|
25
|
+
ENV.to_h.merge(env)
|
26
|
+
end
|
27
|
+
value.gsub(VARIABLE) do |variable|
|
28
|
+
match = $LAST_MATCH_INFO
|
29
|
+
substitute(match, variable, combined_env)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def substitute(match, variable, env)
|
36
|
+
if match[1] == '\\'
|
37
|
+
variable[1..-1]
|
38
|
+
elsif match[3]
|
39
|
+
env.fetch(match[3], "")
|
40
|
+
else
|
41
|
+
variable
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/dotenv/tasks.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Dotenv
|
2
|
+
# Class for creating a template from a env file
|
3
|
+
class EnvTemplate
|
4
|
+
def initialize(env_file)
|
5
|
+
@env_file = env_file
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_template
|
9
|
+
File.open(@env_file, "r") do |env_file|
|
10
|
+
File.open("#{@env_file}.template", "w") do |env_template|
|
11
|
+
env_file.each do |line|
|
12
|
+
var, value = line.split("=")
|
13
|
+
is_a_comment = var.strip[0].eql?("#")
|
14
|
+
line_transform = value.nil? || is_a_comment ? line : "#{var}=#{var}"
|
15
|
+
env_template.puts line_transform
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/dotenv/version.rb
CHANGED
metadata
CHANGED
@@ -1,48 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dotenv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 2.7.6
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Brandon Keepers
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2020-07-11 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rake
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rspec
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
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.40.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.40.0
|
46
55
|
description: Loads environment variables from `.env`.
|
47
56
|
email:
|
48
57
|
- brandon@opensoul.org
|
@@ -51,63 +60,41 @@ executables:
|
|
51
60
|
extensions: []
|
52
61
|
extra_rdoc_files: []
|
53
62
|
files:
|
54
|
-
- .env
|
55
|
-
- .gitignore
|
56
|
-
- .travis.yml
|
57
|
-
- Changelog.md
|
58
|
-
- Gemfile
|
59
|
-
- Guardfile
|
60
63
|
- LICENSE
|
61
64
|
- README.md
|
62
|
-
- Rakefile
|
63
65
|
- bin/dotenv
|
64
|
-
- dotenv-rails.gemspec
|
65
|
-
- dotenv.gemspec
|
66
|
-
- lib/dotenv-rails.rb
|
67
66
|
- lib/dotenv.rb
|
68
|
-
- lib/dotenv/
|
69
|
-
- lib/dotenv/capistrano/recipes.rb
|
67
|
+
- lib/dotenv/cli.rb
|
70
68
|
- lib/dotenv/environment.rb
|
71
|
-
- lib/dotenv/
|
72
|
-
- lib/dotenv/
|
69
|
+
- lib/dotenv/load.rb
|
70
|
+
- lib/dotenv/missing_keys.rb
|
71
|
+
- lib/dotenv/parser.rb
|
72
|
+
- lib/dotenv/substitutions/command.rb
|
73
|
+
- lib/dotenv/substitutions/variable.rb
|
73
74
|
- lib/dotenv/tasks.rb
|
75
|
+
- lib/dotenv/template.rb
|
74
76
|
- lib/dotenv/version.rb
|
75
|
-
- spec/dotenv/environment_spec.rb
|
76
|
-
- spec/dotenv_spec.rb
|
77
|
-
- spec/fixtures/exported.env
|
78
|
-
- spec/fixtures/plain.env
|
79
|
-
- spec/fixtures/quoted.env
|
80
|
-
- spec/fixtures/yaml.env
|
81
|
-
- spec/spec_helper.rb
|
82
77
|
homepage: https://github.com/bkeepers/dotenv
|
83
|
-
licenses:
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata: {}
|
84
81
|
post_install_message:
|
85
82
|
rdoc_options: []
|
86
83
|
require_paths:
|
87
84
|
- lib
|
88
85
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
86
|
requirements:
|
91
|
-
- -
|
87
|
+
- - ">="
|
92
88
|
- !ruby/object:Gem::Version
|
93
89
|
version: '0'
|
94
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
91
|
requirements:
|
97
|
-
- -
|
92
|
+
- - ">="
|
98
93
|
- !ruby/object:Gem::Version
|
99
94
|
version: '0'
|
100
95
|
requirements: []
|
101
|
-
|
102
|
-
rubygems_version: 1.8.23
|
96
|
+
rubygems_version: 3.0.3
|
103
97
|
signing_key:
|
104
|
-
specification_version:
|
98
|
+
specification_version: 4
|
105
99
|
summary: Loads environment variables from `.env`.
|
106
|
-
test_files:
|
107
|
-
- spec/dotenv/environment_spec.rb
|
108
|
-
- spec/dotenv_spec.rb
|
109
|
-
- spec/fixtures/exported.env
|
110
|
-
- spec/fixtures/plain.env
|
111
|
-
- spec/fixtures/quoted.env
|
112
|
-
- spec/fixtures/yaml.env
|
113
|
-
- spec/spec_helper.rb
|
100
|
+
test_files: []
|